善意的投票(最大流)
善意的投票
https://www.lydsy.com/JudgeOnline/problem.php?id=1934
Submit: 2741 Solved: 1735
[Submit][Status][Discuss]
Description
幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。 我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?
Input
第一行只有两个整数n,m,保证有2≤n≤300,1≤m≤n(n-1)/2。其中n代表总人数,m代表好朋友的对数。文件第二行有n个整数,第i个整数代表第i个小朋友的意愿,当它为1时表示同意睡觉,当它为0时表示反对睡觉。接下来文件还有m行,每行有两个整数i,j。表示i,j是一对好朋友,我们保证任何两对i,j不会重复。
Output
只需要输出一个整数,即可能的最小冲突数。
Sample Input
3 3
1 0 0
1 2
1 3
3 2
1 0 0
1 2
1 3
3 2
Sample Output
1
HINT
在第一个例子中,所有小朋友都投赞成票就能得到最优解
把赞同和反对的分成两部分,分别从源点和汇点拉边
1 #include<iostream> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<cstdio> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #define maxn 100005 11 #define MAXN 10005 12 #define mem(a,b) memset(a,b,sizeof(a)) 13 const int N=200005; 14 const int M=200005; 15 const int INF=0x3f3f3f3f; 16 using namespace std; 17 int n; 18 struct Edge{ 19 int v,next; 20 int cap,flow; 21 }edge[MAXN*20];//注意这里要开的够大。。不然WA在这里真的想骂人。。问题是还不报RE。。 22 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN]; 23 int cnt=0;//实际存储总边数 24 void isap_init() 25 { 26 cnt=0; 27 memset(pre,-1,sizeof(pre)); 28 } 29 void isap_add(int u,int v,int w)//加边 30 { 31 edge[cnt].v=v; 32 edge[cnt].cap=w; 33 edge[cnt].flow=0; 34 edge[cnt].next=pre[u]; 35 pre[u]=cnt++; 36 } 37 void add(int u,int v,int w){ 38 isap_add(u,v,w); 39 isap_add(v,u,w); 40 } 41 bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长 42 { 43 memset(dep,-1,sizeof(dep)); 44 memset(gap,0,sizeof(gap)); 45 gap[0]=1; 46 dep[t]=0; 47 queue<int>q; 48 while(!q.empty()) 49 q.pop(); 50 q.push(t);//从汇点开始反向建层次图 51 while(!q.empty()) 52 { 53 int u=q.front(); 54 q.pop(); 55 for(int i=pre[u];i!=-1;i=edge[i].next) 56 { 57 int v=edge[i].v; 58 if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量 59 { 60 dep[v]=dep[u]+1; 61 gap[dep[v]]++; 62 q.push(v); 63 //if(v==sp)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定 64 //break; 65 } 66 } 67 } 68 return dep[s]!=-1; 69 } 70 int isap(int s,int t) 71 { 72 if(!bfs(s,t)) 73 return 0; 74 memcpy(cur,pre,sizeof(pre)); 75 //for(int i=1;i<=n;i++) 76 //cout<<"cur "<<cur[i]<<endl; 77 int u=s; 78 path[u]=-1; 79 int ans=0; 80 while(dep[s]<n)//迭代寻找增广路,n为节点数 81 { 82 if(u==t) 83 { 84 int f=INF; 85 for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路 86 f=min(f,edge[i].cap-edge[i].flow); 87 for(int i=path[u];i!=-1;i=path[edge[i^1].v]) 88 { 89 edge[i].flow+=f; 90 edge[i^1].flow-=f; 91 } 92 ans+=f; 93 u=s; 94 continue; 95 } 96 bool flag=false; 97 int v; 98 for(int i=cur[u];i!=-1;i=edge[i].next) 99 { 100 v=edge[i].v; 101 if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow) 102 { 103 cur[u]=path[v]=i;//当前弧优化 104 flag=true; 105 break; 106 } 107 } 108 if(flag) 109 { 110 u=v; 111 continue; 112 } 113 int x=n; 114 if(!(--gap[dep[u]]))return ans;//gap优化 115 for(int i=pre[u];i!=-1;i=edge[i].next) 116 { 117 if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x) 118 { 119 x=dep[edge[i].v]; 120 cur[u]=i;//常数优化 121 } 122 } 123 dep[u]=x+1; 124 gap[dep[u]]++; 125 if(u!=s)//当前点没有增广路则后退一个点 126 u=edge[path[u]^1].v; 127 } 128 return ans; 129 } 130 131 int main(){ 132 int m,s,t; 133 cin>>n>>m; 134 int a,b,c; 135 isap_init(); 136 s=0,t=n+1; 137 for(int i=1;i<=n;i++){ 138 cin>>a; 139 if(a){ 140 add(s,i,1); 141 } 142 else{ 143 add(i,t,1); 144 } 145 } 146 for(int i=1;i<=m;i++){ 147 cin>>a>>b; 148 add(a,b,1); 149 } 150 n=n+2; 151 cout<<isap(s,t)<<endl; 152 } 153 /* 154 3 3 155 1 0 0 156 1 2 157 1 3 158 3 2 159 */
posted on 2018-10-27 16:28 Fighting_sh 阅读(201) 评论(0) 编辑 收藏 举报