《最小割模型在信息学竞赛中的应用》最优标号

题意:定义两点边权值等于点权异或值,给出一些点权值,求如何给其他点标号使所有边权之和最小。

题解:根据异或的性质,我们可以单独确定每一个二进制位的最小值。对于每一位来讲:考虑这一位如果为1与源点连边,否则与汇点连边。那么与源点相连的点集集合内贡献为0,与汇点相连的点集集合内贡献为0,对答案贡献的只有集合之间的边,且每条边贡献为1,要最小化贡献值,即求最小割。为了保证最小值在原图的边内,与汇点源点相连的边权值设为正无穷,原图的边权值设为1。

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=510,M=(3010+N*2)*2,inf=1e9;
 5 int h[N],e[M],ne[M],f[M],idx;
 6 int cur[N],d[N],p[N];
 7 int n,m,S,T;
 8 struct node
 9 {
10     int x,y;
11 }edges[M];
12 int k;
13 void add(int a,int b,int c,int d)
14 {
15     ne[idx]=h[a],e[idx]=b,f[idx]=c,h[a]=idx++;
16     ne[idx]=h[b],e[idx]=a,f[idx]=d,h[b]=idx++;
17 }
18 void bulid(int x)
19 {
20     memset(h,-1,sizeof h);
21     idx=0;
22     for(int i=0;i<m;i++)
23     add(edges[i].x,edges[i].y,1,1);
24     for(int i=1;i<=n;i++)
25         if(p[i])
26         {
27             if(p[i]>>x&1)add(S,i,inf,inf);
28             else add(i,T,inf,inf);
29         }
30 }
31 bool bfs()
32 {
33     memset(d,-1,sizeof d);
34     queue<int>q;
35     q.push(S);
36     d[S]=0;
37     cur[S]=h[S];
38     while(q.size())
39     {
40         int t=q.front();
41         q.pop();
42         for(int i=h[t];i!=-1;i=ne[i])
43         {
44             int j=e[i];
45             if(d[j]==-1&&f[i])
46             {
47                 d[j]=d[t]+1;
48                 cur[j]=h[j];
49                 if(j==T)return true;
50                 q.push(j);
51             }
52         }
53     }
54     return false;
55 }
56 int find(int u,int limit)
57 {
58     if(u==T)return limit;
59     int flow=0;
60     for(int i=cur[u];i!=-1&&flow<limit;i=ne[i])
61     {
62         int j=e[i];
63         cur[u]=i;
64         if(d[j]==d[u]+1&&f[i])
65         {
66             int t=find(j,min(f[i],limit-flow));
67             if(!t)d[j]=-1;
68             f[i]-=t,f[i^1]+=t,flow+=t;
69         }
70     }
71     return flow;
72 }
73 ll dinic(int x)
74 {
75     bulid(x);
76     int r=0,flow;
77     while(bfs())while(flow=find(S,inf))r+=flow;
78     return r;
79 }
80 int main()
81 {
82     S=0,T=N-1;
83     cin>>n>>m;
84     for(int i=0;i<m;i++)scanf("%d%d",&edges[i].x,&edges[i].y);
85     cin>>k;
86     for(int i=0;i<k;i++)
87     {
88         int u,v;
89         scanf("%d%d",&u,&v);
90         p[u]=v;
91     }
92     long long ans=0;
93     for(int i=0;i<31;i++)ans+=dinic(i)<<i;
94     cout<<ans<<endl;
95     return 0;
96 }
原文地址:https://www.cnblogs.com/flyljz/p/13678750.html