【SPOJ839】Optimal Marks 网络流

You are given an undirected graph G(V, E). Each vertex has a mark which is an integer from the range [0..231 – 1]. Different vertexes may have the same mark.

For an edge (u, v), we define Cost(u, v) = mark[u] xor mark[v].

Now we know the marks of some certain nodes. You have to determine the marks of other nodes so that the total cost of edges is as small as possible.

 

Input

The first line of the input data contains integer T (1 ≤ T ≤ 10) - the number of testcases. Then the descriptions of T testcases follow.

First line of each testcase contains 2 integers N and M (0 < N <= 500, 0 <= M <= 3000). N is the number of vertexes and M is the number of edges. Then M lines describing edges follow, each of them contains two integers u, v representing an edge connecting u and v.

Then an integer K, representing the number of nodes whose mark is known. The next K lines contain 2 integers u and p each, meaning that node u has a mark p. It’s guaranteed that nodes won’t duplicate in this part.

Output

For each testcase you should print N lines integer the output. The Kth line contains an integer number representing the mark of node K. If there are several solutions, you have to output the one which minimize the sum of marks. If there are several solutions, just output any of them.

Example

Input:
1
3 2
1 2
2 3
2
1 5
3 100

Output:
5
4
100 

题目大意:
每一条边的权值定义为x xor y,(x,y是两端点),有一些点的权值已知,求剩下的点怎么弄,是总边权最小。
题解:
首先要知道xor操作时,二进制的每一位都是独立的,不相互影响,所以可以分开处理。
对于每一位,我们把未知的点初始为0,然后对已知的进行操作:当前位为1的S到i有一条边,容量为INF,为0则到T有一条为INF边。
然后对于每一条边:(i,j)拆成(i,j,1)(j,i,1)
然后跑最小割,可以发现对于每一个子图,最小割不是割在T就是割在S,割在T表示前面一堆点都设为1(
因为已知的1比0多),隔在S表示后面一堆点都设为0(因为已知的0比1多)
知道了这个,于是在跑完最小割之后就从S开始把能到的点都标为1。
至于反向弧为什么为1,一是原图无向,二就是为了这个时候能全都遍历到。
贴代码:
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=605,M=3005,INF=1999999999;
  7 int gi(){
  8     int str=0;char ch=getchar();
  9     while(ch>'9'||ch<'0')ch=getchar();
 10     while(ch>='0'&&ch<='9')str=str*10+ch-'0',ch=getchar();
 11     return str;
 12 }
 13 int n,m,mark[N];
 14 struct Edge{
 15     int x,y;
 16 }e[M];
 17 bool d[N];bool vis[N];
 18 int num=1,head[N],S=0,T;
 19 struct Lin{
 20     int next,to,dis;
 21 }a[M*10];
 22 void init(int x,int y,int z){
 23     a[++num].next=head[x];
 24     a[num].to=y;
 25     a[num].dis=z;
 26     head[x]=num;
 27     a[++num].next=head[y];
 28     a[num].to=x;
 29     a[num].dis=(z==INF?INF:1);
 30     head[y]=num;
 31 }
 32 int q[N],dep[N];
 33 bool bfs()
 34 {
 35     memset(dep,0,sizeof(dep));
 36     dep[S]=1;q[1]=S;int u,x,sum=1,t=0;
 37     while(t!=sum)
 38     {
 39         x=q[++t];
 40         for(int i=head[x];i;i=a[i].next){
 41             u=a[i].to;
 42             if(dep[u]||a[i].dis<=0)continue;
 43             dep[u]=dep[x]+1;q[++sum]=u;
 44         }
 45     }
 46     return dep[T];
 47 }
 48 int dfs(int x,int flow)
 49 {
 50     if(x==T || !flow)return flow;
 51     int tmp,sum=0,u;
 52     for(int i=head[x];i;i=a[i].next){
 53         u=a[i].to;
 54         if(dep[u]!=dep[x]+1 || a[i].dis<=0)continue;
 55         tmp=dfs(u,min(flow,a[i].dis));
 56         sum+=tmp;flow-=tmp;
 57         a[i].dis-=tmp;a[i^1].dis+=tmp;
 58         if(!flow)break;
 59     }
 60     return sum;
 61 }
 62 void maxflow(){
 63     int tmp;
 64     while(bfs()){
 65         tmp=dfs(S,INF);
 66         while(tmp)tmp=dfs(S,INF);
 67     }
 68 }
 69 void Reset(){
 70     memset(head,0,sizeof(head));
 71     memset(vis,0,sizeof(vis));
 72     num=1;
 73 }
 74 void remark(int x,int pa){
 75     vis[x]=true;
 76     if(!d[x])mark[x]+=pa;
 77     for(int i=head[x];i;i=a[i].next){
 78         if(a[i].dis>0 && !vis[a[i].to])remark(a[i].to,pa);
 79     }
 80 }
 81 void check(int fx)
 82 {
 83     Reset();
 84     int pa=(1<<fx);
 85     for(int i=1;i<=n;i++){
 86         if(!d[i])continue;
 87         if(mark[i]&pa)init(S,i,INF);
 88         else init(i,T,INF);
 89     }
 90     for(int i=1;i<=m;i++)init(e[i].x,e[i].y,1);
 91     maxflow();
 92     remark(S,pa);
 93 }
 94 void work()
 95 {
 96     int pp,x;
 97     n=gi();m=gi();
 98     T=n+1;
 99     for(int i=1;i<=m;i++)e[i].x=gi(),e[i].y=gi();
100     pp=gi();
101     for(int i=1;i<=pp;i++)x=gi(),mark[x]=gi(),d[x]=true;
102     for(int i=0;i<=30;i++)check(i);
103     for(int i=1;i<=n;i++)printf("%d\n",mark[i]);
104 }
105 void Clear(){
106     memset(mark,0,sizeof(mark));
107     memset(d,0,sizeof(d));
108 }
109 int main()
110 {
111     //freopen("pp.in","r",stdin);
112     int TT=gi();
113     while(TT--){
114         work();
115         Clear();
116     }
117     return 0;
118 }
 
 

 

 



转载于:https://www.cnblogs.com/Yuzao/p/6867023.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值