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.node
For an edge (u, v), we define Cost(u, v) = mark[u] xor mark[v].ios
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.算法
The first line of the input data contains integer T (1 ≤ T ≤ 10) - the number of testcases. Then the descriptions of T testcases follow.markdown
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.ui
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.this
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.spa
Examplecode
Input:
1
3 2
1 2
2 3
2
1 5
3 100圖片
Output:
5
4
100 ip
在Amber的最小割論文上看到的一道題。
考慮到是異或運算求最小cost之和,因爲對於二進制,各個位之間是互不影響的,因此能夠將問題轉會爲每一個二進制位的求解,而後求和便可。對於每一個二進制位,要麼爲0,要麼爲1, 就想到將整個圖切割成兩個點
集,即對於每一個點,都只有兩種取值,能夠當作是要將點集劃分紅兩類。在這種分類思想的指導下,從新考察操做的意義:對於邊的兩個端點,若它們同類則邊權無值;若它們異類則邊權有值1。
建一源點S,匯點T
對於已經標號過的點:
1. 對於位爲1的點建邊 < S, V, INF, 0>
2. 對於位爲0的點建邊 < V, T, INF, 0>
對於全部的原邊
建成流量爲1的雙向邊< u, v, 1, 1>
這樣求得最小割,即爲當前位的最優解。
這樣建邊,求最小割時,保證了割邊都是原邊,求完後,全部與S相連的點能夠標號爲1, 全部與T相連的邊標號爲0, 那麼這些割邊即爲相鄰點異類的邊,同時保證了他們的和最小。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MaxN = 550;
const int MaxM = 3100;
typedef struct node
{
int u,v;
}Point;
typedef struct Node
{
int v,next,cap;
}edge ;
Point a[MaxM];
edge e[MaxM*10];
int mark[MaxN],vis[MaxN],Ans[MaxN];
int H[MaxN];
int n,m,k,s,t,top;
void AddEdge(int u,int v,int w1,int w2)
{
e[top].v = v; e[top].cap = w1;
e[top].next = H[u]; H[u]= top++;
e[top].v = u; e[top].cap = w2;
e[top].next = H[v]; H[v] = top++;
}
bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int>Q;
vis[s] = 1;
Q.push(s);
while(!Q.empty())
{
int u =Q.front();
Q.pop();
for(int i=H[u];~i;i=e[i].next)
{
if(e[i].cap>0&&!vis[e[i].v])
{
vis[e[i].v] = vis[u]+1;
Q.push(e[i].v);
}
}
}
return vis[t];
}
int DFS(int u,int cap)
{
if(u==t)
{
return cap;
}
int ans = 0;
for(int i=H[u];~i;i=e[i].next)
{
if(e[i].cap>0&&vis[e[i].v]==vis[u]+1)
{
int ant = DFS(e[i].v,min(e[i].cap,cap));
ans += ant;
cap -= ant;
e[i].cap-=ant;
e[i^1].cap+=ant;
if(cap==0)
{
break;
}
}
}
return ans;
}
void Dinic()
{
while(BFS())
{
DFS(s,INF);
}
}
void dfs(int u,int bite)
{
vis[u] = 1;
Ans[u]+=bite;
for(int i = H[u];i!=-1;i=e[i].next)//和S相連都爲1
{
if(e[i].cap>0&&!vis[e[i].v])
{
dfs(e[i].v,bite);
}
}
}
void Solve()
{
int bite=1;
memset(Ans,0,sizeof(Ans));
while(1)
{
top = 0;
memset(H,-1,sizeof(H));
for(int i=1;i<=m;i++)
{
AddEdge(a[i].u,a[i].v,1,1);
}
bool flag=false;
for(int i=1;i<=n;i++) //以每一位求一次最小割
{
if(mark[i]!=-1)
{
if(mark[i]>=1)
{
flag=true;
}
if(mark[i]%2)
{
AddEdge(s,i,INF,0);
}
else
{
AddEdge(i,t,INF,0);
}
mark[i]>>=1;
}
}
if(!flag)//都爲零的時候算法結束
{
break;
}
Dinic();
memset(vis,0,sizeof(vis));
dfs(s,bite);
bite<<=1;
}
for(int i=1;i<=n;i++)
{
if(i!=1) printf(" ");
printf("%d",Ans[i]);
}
puts("");
}
int main()
{
int T;
scanf("%d",&T);
int u,v,w;
while(T--)
{
scanf("%d %d",&n,&m);
s=0,t=n+1;
for(int i=1;i<=m;i++) scanf("%d %d",&a[i].u,&a[i].v);
scanf("%d",&k);
memset(mark,-1,sizeof(mark));
for(int i=1;i<=k;i++)
{
scanf("%d %d",&u,&w);
mark[u] = w;
}
Solve();
}
return 0;
}