codeforces 863F Almost Permutation 费用流 好题!
来源:互联网 发布:移动免费流量软件 编辑:程序博客网 时间:2024/05/18 03:11
Recently Ivan noticed an array a while debugging his code. Now Ivan can't remember this array, but the bug he was trying to fix didn't go away, so Ivan thinks that the data from this array might help him to reproduce the bug.
Ivan clearly remembers that there were n elements in the array, and each element was not less than 1 and not greater than n. Also he remembers q facts about the array. There are two types of facts that Ivan remembers:
- 1 li ri vi — for each x such that li ≤ x ≤ ri ax ≥ vi;
- 2 li ri vi — for each x such that li ≤ x ≤ ri ax ≤ vi.
Also Ivan thinks that this array was a permutation, but he is not so sure about it. He wants to restore some array that corresponds to the qfacts that he remembers and is very similar to permutation. Formally, Ivan has denoted the cost of array as follows:
, where cnt(i) is the number of occurences of i in the array.
Help Ivan to determine minimum possible cost of the array that corresponds to the facts!
The first line contains two integer numbers n and q (1 ≤ n ≤ 50, 0 ≤ q ≤ 100).
Then q lines follow, each representing a fact about the array. i-th line contains the numbers ti, li, ri and vi for i-th fact (1 ≤ ti ≤ 2, 1 ≤ li ≤ ri ≤ n, 1 ≤ vi ≤ n, ti denotes the type of the fact).
If the facts are controversial and there is no array that corresponds to them, print -1. Otherwise, print minimum possible cost of the array.
3 0
3
3 11 1 3 2
5
3 21 1 3 22 1 3 2
9
3 21 1 3 22 1 3 1
-1
这道题的建图方法非常的巧妙。
我们根据给出的条件,确定每个元素所处于的区间范围,表明这个元素应该在这个区间[min[i],max[i]]内取值。
我们从源点0出发,向每个元素1,2,3...n连接一条容量为1,费用为0的边,表示选取这个元素。
然后从第i个元素向[min[i],max[i]]中的所有元素j连接一条容量为1,费用为0的边,代表给元素i赋值为j。
下面就是关键了:
从i+n 向 汇点2*n+1连接n条边,每条边的容量都是1,但是费用从1,3,5,。。。不等。
然后跑一边最小费用最大流就可以了。
为什么这么做是正确的呢?
我们想,假设有t个元素都流向的第i+n个节点,这意味着t个元素都赋值为了i。
当t = 1时,一定会选择费用为1的边流,total cost = 1=1*1
当t = 2时,一定会选择费用为1,3的边流,total cost = 1+3=2*2
当t = 3时,一定会选择费用为1,3,5的边流,total cost = 1+3+5=3*3
当t = 4时,一定会选择费用为1,3,5,7的边流,total cost = 1+3+5+7=4*4
在这里利用了平方数的一个性质,非常巧妙。
代码:
#include<bits/stdc++.h>using namespace std;const int inf = 1e9;const int mm = 111111;const int maxn = 999;int node,src,dest,edge;int ver[mm],flow[mm],cst[mm],nxt[mm];int head[maxn],work[maxn],dis[maxn],q[maxn];int tot_cost;void prepare(int _node,int _src,int _dest){ node=_node,src=_src,dest=_dest; for(int i=0; i<node; ++i)head[i]=-1; edge=0; tot_cost = 0;}void add_edge(int u,int v,int c,int cost){ ver[edge]=v,flow[edge]=c,nxt[edge]=head[u],cst[edge]=cost,head[u]=edge++; ver[edge]=u,flow[edge]=0,nxt[edge]=head[v],cst[edge]=-cost,head[v]=edge++;}/**广搜计算出每个点与源点的最短距离,如果不能到达汇点说明算法结束*/int ins[maxn];int pre[maxn];bool Dinic_spfa(){memset(ins,0,sizeof(ins));memset(dis,-1,sizeof(dis));memset(pre,-1,sizeof(pre));queue<int> Q; //int i,u,v,l,r=0; Q.push(src); dis[src] = 0,ins[src] = 1; pre[src] = -1; while(!Q.empty()){ int u = Q.front();Q.pop();ins[u] = 0;for(int e = head[u];e != -1;e = nxt[e]){int v = ver[e];if(!flow[e]) continue;if(dis[v] < 0 || dis[v] > dis[u] + cst[e]){dis[v] = dis[u] + cst[e];pre[v] = e;if(!ins[v]) ins[v] = 1,Q.push(v);}} } return dis[dest] != -1;}int Dinic_flow(){ int i,ret=0,delta=inf; while(Dinic_spfa()) { for(int i=pre[dest];i != -1;i = pre[ver[i^1]]) delta = min(delta,flow[i]);for(int i=pre[dest];i != -1;i = pre[ver[i^1]]) flow[i] -= delta,flow[i^1] += delta;ret+=delta;tot_cost += dis[dest]*delta; } return ret;}int getint() { int x = 0, flag = 0; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if (ch == '-') flag = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; return flag ? -x : x;}int n,m;int mi[100],ma[100];int main(){n = getint();m = getint();prepare(2*n+2,0,2*n+1);for(int i = 1;i <= n;++i){mi[i] = 1;ma[i] = n;}while(m--){int tp,l,r,v;tp = getint();l = getint();r = getint();v = getint();for(int i = l;i <= r;++i){if(tp == 1)mi[i] = max(mi[i],v);elsema[i] = min(ma[i],v);if(mi[i] > ma[i] || mi[i] < 1 || ma[i] > n) return 0*puts("-1");}} for(int i = 1;i <= n;i++) add_edge(0,i,1,0);for(int i = 1;i <= n;i++) for(int j = mi[i];j <= ma[i];++j)add_edge(i,j+n,1,0);for(int i = n+1;i <= 2*n;++i) for(int j = 0;j < n;++j)add_edge(i,2*n+1,1,2*j+1);int f = Dinic_flow();cout<<tot_cost<<endl;}
附费用流模板:
#include<bits/stdc++.h>using namespace std;const int inf = 1e9;const int mm = 111111;const int maxn = 999;int node,src,dest,edge;int ver[mm],flow[mm],cst[mm],nxt[mm];int head[maxn],work[maxn],dis[maxn],q[maxn];int tot_cost;void prepare(int _node,int _src,int _dest){ node=_node,src=_src,dest=_dest; for(int i=0; i<node; ++i)head[i]=-1; edge=0; tot_cost = 0;}void add_edge(int u,int v,int c,int cost){ ver[edge]=v,flow[edge]=c,nxt[edge]=head[u],cst[edge]=cost,head[u]=edge++; ver[edge]=u,flow[edge]=0,nxt[edge]=head[v],cst[edge]=-cost,head[v]=edge++;}/**广搜计算出每个点与源点的最短距离,如果不能到达汇点说明算法结束*/int ins[maxn];int pre[maxn];bool Dinic_spfa(){memset(ins,0,sizeof(ins));memset(dis,-1,sizeof(dis));memset(pre,-1,sizeof(pre));queue<int> Q; //int i,u,v,l,r=0; Q.push(src); dis[src] = 0,ins[src] = 1; pre[src] = -1; while(!Q.empty()){ int u = Q.front();Q.pop();ins[u] = 0;for(int e = head[u];e != -1;e = nxt[e]){int v = ver[e];if(!flow[e]) continue;if(dis[v] < 0 || dis[v] > dis[u] + cst[e]){dis[v] = dis[u] + cst[e];pre[v] = e;if(!ins[v]) ins[v] = 1,Q.push(v);}} } return dis[dest] != -1;}int Dinic_flow(){ int i,ret=0,delta=inf; while(Dinic_spfa()) { for(int i=pre[dest];i != -1;i = pre[ver[i^1]]) delta = min(delta,flow[i]);for(int i=pre[dest];i != -1;i = pre[ver[i^1]]) flow[i] -= delta,flow[i^1] += delta;ret+=delta;tot_cost += dis[dest]*delta; } return ret;}int getint() { int x = 0, flag = 0; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if (ch == '-') flag = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; return flag ? -x : x;}
- codeforces 863F Almost Permutation 费用流 好题!
- codeforces 863F Almost Permutation
- F. Almost Permutation
- Codeforces 362 E Petya and Pipes【费用流】好题
- codeforces 717 G. Underfail(费用流,好题)
- codeforces 884F 费用流,图解很清晰
- 【Codeforces】452F Permutation hash+线段树
- 【线段树+Hash】Codeforces 452F Permutation
- Codeforces 452F Permutation【线段树】【哈希】
- [线段树+哈希] Codeforces 452F. Permutation
- 【codeforces 731F】【前缀和 分块求和 好题】F. Video Cards
- Codeforces Round #277.5(Div. 2) F. Special Matrices【思维+Dp】好题~好题~
- Almost Identity Permutations CodeForces
- Codeforces Round #376 (Div. 2) F. Video Cards(前缀和,好题)
- Codeforces Round #376 (Div. 2) F. Video Cards(前缀和,好题)
- Codeforces Canada Cup 2016 F. Family Photos 博弈 策略分析 好题
- Codeforces Round #322 (Div. 2) F. Zublicanes and Mumocrates(树形dp,好题)
- Codeforces 732F Tourist Reform【思维+边双联通+Dfs处理后继问题】好题!
- 【每日一句shell】vim、sed新姿势 | 一次性给文件多行加注释
- 在Ubuntu16.04下搭建 Smaba服务器
- 九九乘法表
- 校园招聘季,你真的准备好了吗?
- RedHat 更新CentOS Yum源
- codeforces 863F Almost Permutation 费用流 好题!
- IO多路复用
- 面试过程中没来得及细读的文章
- 判断一个字符串的字符重新排列后,能否变成另一个字符串。
- Asp.net面试题
- Leetcode c语言-Search Insert Position
- mybatis中#和$符号的区别
- [US Giants] 十. Data Structure
- 健身教练课程目录