SPOJ 839 Optimal Marks(最小割的应用)

https://vjudge.net/problem/SPOJ-OPTM

题意:

给出一个无向图G,每个点 v 以一个有界非负整数 lv 作为标号,每条边e=(u,v)的权w定义为该边的两个端点的标号的异或值,即W=lu XOR lv。现已知其中部分点的标号,求使得该图的总边权和最小的标号赋值。即最小化:

 

思路:

这道题目在刘伯涛的论文里讲得十分的详细,看看论文就可以啦。

XOR运算是根据二进制的每一位来计算的,,并且因为每一位都是相互独立的,互不影响,所以可以转化为下式:

接下来对于每一位都新建图,对于已经标号的顶点来说,如果该位是1,则与源点相连,否则与汇点相连,容量均为INF。如果本来就相连的点还是需要相连的,容量为1。对于每个还没有标号的点来说,在这一位的取值要么是1,要么是0,这就很符合最小割。在跑完最大流之后,只需要从源点出发,凡是能到达的点都是取值为1的。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef pair<int,int> pll;
 14 const int INF = 0x3f3f3f3f;
 15 const int maxn = 5000 + 5;
 16 
 17 int n, m, k;
 18 int val[maxn];
 19 int ans[maxn];
 20 int vis[maxn];
 21 int mp[maxn][maxn];
 22 
 23 struct Edge
 24 {
 25     int from,to,cap,flow;
 26     Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){}
 27 };
 28 
 29 struct Dinic
 30 {
 31     int n,m,s,t;
 32     vector<Edge> edges;
 33     vector<int> G[maxn];
 34     bool vis[maxn];
 35     int cur[maxn];
 36     int d[maxn];
 37 
 38     void init(int n)
 39     {
 40         this->n=n;
 41         for(int i=0;i<n;++i) G[i].clear();
 42         edges.clear();
 43     }
 44 
 45     void AddEdge(int from,int to,int cap)
 46     {
 47         edges.push_back( Edge(from,to,cap,0) );
 48         edges.push_back( Edge(to,from,0,0) );
 49         m=edges.size();
 50         G[from].push_back(m-2);
 51         G[to].push_back(m-1);
 52     }
 53 
 54     bool BFS()
 55     {
 56         queue<int> Q;
 57         memset(vis,0,sizeof(vis));
 58         vis[s]=true;
 59         d[s]=0;
 60         Q.push(s);
 61         while(!Q.empty())
 62         {
 63             int x=Q.front(); Q.pop();
 64             for(int i=0;i<G[x].size();++i)
 65             {
 66                 Edge& e=edges[G[x][i]];
 67                 if(!vis[e.to] && e.cap>e.flow)
 68                 {
 69                     vis[e.to]=true;
 70                     d[e.to]=d[x]+1;
 71                     Q.push(e.to);
 72                 }
 73             }
 74         }
 75         return vis[t];
 76     }
 77 
 78     int DFS(int x,int a)
 79     {
 80         if(x==t || a==0) return a;
 81         int flow=0, f;
 82         for(int &i=cur[x];i<G[x].size();++i)
 83         {
 84             Edge &e=edges[G[x][i]];
 85             if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0)
 86             {
 87                 e.flow +=f;
 88                 edges[G[x][i]^1].flow -=f;
 89                 flow +=f;
 90                 a -=f;
 91                 if(a==0) break;
 92             }
 93         }
 94         return flow;
 95     }
 96 
 97     int Maxflow(int s,int t)
 98     {
 99         this->s=s; this->t=t;
100         int flow=0;
101         while(BFS())
102         {
103             memset(cur,0,sizeof(cur));
104             flow +=DFS(s,INF);
105         }
106         return flow;
107     }
108 }DC;
109 
110 void dfs(int u, int x)
111 {
112     vis[u]=1;
113     ans[u]+=x;
114     for(int i=0;i<DC.G[u].size();i++)
115     {
116         Edge& e=DC.edges[DC.G[u][i]];
117         if(!vis[e.to] && e.cap>e.flow)
118             dfs(e.to,x);
119     }
120 }
121 
122 void solve()
123 {
124     int src=0,dst=n+1;
125     int bite=1;
126     while(true)
127     {
128         DC.init(dst+1);
129         for(int i=1;i<=n;i++)
130             for(int j=1;j<=n;j++)
131             if(mp[i][j]) DC.AddEdge(i,j,1);
132 
133         bool flag=false;
134         for(int i=1;i<=n;i++) 
135         {
136             if(val[i]!=-1)
137             {
138                 if(val[i]>=1)
139                 {
140                     flag=true;
141                 }
142                 if(val[i]&1)
143                 {
144                     DC.AddEdge(src,i,INF);
145                 }
146                 else
147                 {
148                     DC.AddEdge(i,dst,INF);
149                 }
150                 val[i]>>=1;
151             }
152         }
153 
154         if(!flag)  break;
155         DC.Maxflow(src,dst);
156         memset(vis,0,sizeof(vis));
157         dfs(src,bite);
158         bite<<=1;
159     }
160 }
161 
162 int main()
163 {
164     //freopen("in.txt","r",stdin);
165     int T;
166     scanf("%d",&T);
167     while(T--)
168     {
169         memset(mp,0,sizeof(mp));
170         scanf("%d%d",&n,&m);
171         for(int i=0;i<m;i++)
172         {
173             int u,v;
174             scanf("%d%d",&u,&v);
175             mp[u][v]=mp[v][u]=1;
176         }
177         memset(val,-1,sizeof(val));
178         scanf("%d",&k);
179         for(int i=0;i<k;i++)
180         {
181             int u,v;
182             scanf("%d%d",&u,&v);
183             val[u]=v;
184         }
185         memset(ans,0,sizeof(ans));
186         solve();
187         for(int i=1;i<=n;i++)
188         {
189             printf("%d\n",ans[i]);
190         }
191     }
192     return 0;
193 }

 

转载于:https://www.cnblogs.com/zyb993963526/p/7643114.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值