spoj 839 Optimal Marks(二进制位,最小割)
【题目链接】
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17875
【题意】
给定一个图,图的权定义为边的两端点相抑或值的和。问如何给没有权值的点分配权值使得图的权值最小。
【思路】
考虑每一二进制位i,即我们要依次确定每一二进制位且构造该二进制位的最优方案,建图如下:
- (S,u,inf) u的i位为0
- (u,T,inf) u的i位为1
- (u,v,1)(v,u,1) u,v之间有边相连
S集第i位为0,T集第i位为1,该图的一个最小割中的边的两端是第i位不同的两个点,所以最小割即为产生抑或值,且是最小值。
然后更新T集中点的点值。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 1e4+10; 15 const int inf = 1e9; 16 17 ll read() { 18 char c=getchar(); 19 ll f=1,x=0; 20 while(!isdigit(c)) { 21 if(c=='-') f=-1; c=getchar(); 22 } 23 while(isdigit(c)) 24 x=x*10+c-'0',c=getchar(); 25 return x*f; 26 } 27 28 struct Edge { 29 int u,v,cap,flow; 30 }; 31 struct Dinic { 32 int n,m,s,t; 33 int d[N],cur[N],vis[N]; 34 vector<int> g[N]; 35 vector<Edge> es; 36 queue<int> q; 37 void init(int n) { 38 this->n=n; 39 es.clear(); 40 FOR(i,0,n) g[i].clear(); 41 } 42 void clear() { 43 FOR(i,0,(int)es.size()-1) es[i].flow=0; 44 } 45 void AddEdge(int u,int v,int w) { 46 es.push_back((Edge){u,v,w,0}); 47 es.push_back((Edge){v,u,0,0}); 48 m=es.size(); 49 g[u].push_back(m-2); 50 g[v].push_back(m-1); 51 } 52 int bfs() { 53 memset(vis,0,sizeof(vis)); 54 q.push(s); d[s]=0; vis[s]=1; 55 while(!q.empty()) { 56 int u=q.front(); q.pop(); 57 FOR(i,0,(int)g[u].size()-1) { 58 Edge& e=es[g[u][i]]; 59 int v=e.v; 60 if(!vis[v]&&e.cap>e.flow) { 61 vis[v]=1; 62 d[v]=d[u]+1; 63 q.push(v); 64 } 65 } 66 } 67 return vis[t]; 68 } 69 int dfs(int u,int a) { 70 if(u==t||!a) return a; 71 int flow=0,f; 72 for(int& i=cur[u];i<g[u].size();i++) { 73 Edge& e=es[g[u][i]]; 74 int v=e.v; 75 if(d[v]==d[u]+1&&(f=dfs(v,min(a,e.cap-e.flow)))>0) { 76 e.flow+=f; 77 es[g[u][i]^1].flow-=f; 78 flow+=f; a-=f; 79 if(!a) break; 80 } 81 } 82 return flow; 83 } 84 int MaxFlow(int s,int t) { 85 this->s=s,this->t=t; 86 int flow=0; 87 while(bfs()) { 88 memset(cur,0,sizeof(cur)); 89 flow+=dfs(s,inf); 90 } 91 return flow; 92 } 93 } dc; 94 95 int T,n,m,s,t,K,u[N],v[N],a[N],vis[N],val[N]; 96 97 void dfs(int u,int x) 98 { 99 vis[u]=1; val[u]+=x; 100 FOR(i,0,(int)dc.g[u].size()-1) { 101 Edge& e=dc.es[dc.g[u][i]^1]; //从T开始 判断反向边 102 if(!vis[e.u]&&e.cap>e.flow) dfs(e.u,x); 103 } 104 } 105 void build(int x) 106 { 107 s=0,t=n+1; 108 dc.init(n+2); 109 FOR(i,1,n) if(a[i]>=0) { 110 if(a[i]&x) dc.AddEdge(i,t,inf); 111 else dc.AddEdge(s,i,inf); 112 } 113 FOR(i,1,m) { 114 dc.AddEdge(u[i],v[i],1); 115 dc.AddEdge(v[i],u[i],1); 116 } 117 } 118 void init() 119 { 120 memset(val,0,sizeof(val)); 121 memset(a,-1,sizeof(a)); 122 } 123 int main() 124 { 125 T=read(); 126 while(T--) { 127 init(); 128 n=read(),m=read(); 129 FOR(i,1,m) 130 u[i]=read(),v[i]=read(); 131 K=read(); 132 FOR(i,1,K) { 133 int u=read(); 134 a[u]=read(); 135 } 136 FOR(i,0,30) { 137 int x=1<<i; 138 build(x); 139 dc.MaxFlow(s,t); 140 memset(vis,0,sizeof(vis)); 141 dfs(t,x); 142 } 143 FOR(i,1,n) 144 if(a[i]>=0) printf("%d\n",a[i]); 145 else printf("%d\n",val[i]); 146 } 147 return 0; 148 }
P.S.太神太巧妙辣 0.0
posted on 2016-03-23 17:48 hahalidaxin 阅读(260) 评论(0) 编辑 收藏 举报