spoj 839 Opitmal marks

 https://www.spoj.pl/problems/OPTM/

                           839. 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 integerT (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 andM is the number of edges. ThenM 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 nextK 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. TheKth line contains an integer number representing the mark of nodeK. 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

题意:一个无向图,某些点已有权值,现在要你确定其他点的权值,使得边权之和最小,边权u,v的权值cost[u][v]= mark[u]^mark[v]。

分析:说不清楚,看胡伯涛论文《最小割模型在信息学中的应用》

手敲一遍最大流,居然敲错了

代码:

#include<stdio.h>
#include<string.h>
#define N 550
#define E 20000
#define inf 0x3f3f3f3f
int e,head[N],dep[N],que[N],cur[N];
char tag[N],flag[N];
int a[N][N];
struct node
{
	int x,y;
	int nxt;
	int c;
}edge[E];
void addedge(int u,int v,int c)
{
	edge[e].x=u;
	edge[e].y=v;
	edge[e].nxt=head[u];
	edge[e].c=c;
	head[u]=e++;

	edge[e].x=v;
	edge[e].y=u;
	edge[e].nxt=head[v];
	edge[e].c=0;
	head[v]=e++;
}

int maxflow(int s,int t)
{
	int i,j,k,front,rear,top,min,res=0;
	while(1)
	{
		memset(dep,-1,sizeof(dep));
		front=0;rear=0;		
		que[rear++]=s;
		dep[s]=0;
		while(front!=rear)
		{
			i=que[front++];
			for(j=head[i];j!=-1;j=edge[j].nxt)
				if(edge[j].c&&dep[edge[j].y]==-1)
				{
					dep[edge[j].y]=dep[i]+1;
					que[rear++]=edge[j].y;			
				}
		}
		if(dep[t]==-1)
			break;
		memcpy(cur,head,sizeof(head)); 
		for(i=s,top=0;;)
		{
			if(i==t)
			{
				min=inf;
				for(k=0;k<top;k++)
					if(min>edge[que[k]].c)
					{
						min=edge[que[k]].c;
						front=k;
					}
				for(k=0;k<top;k++)
				{
					edge[que[k]].c-=min;
					edge[que[k]^1].c+=min;
				}
				res+=min;
				i=edge[que[top=front]].x;
				
			}
			for(j=cur[i];cur[i]!=-1;j=cur[i]=edge[cur[i]].nxt)
				if(dep[edge[j].y]==dep[i]+1&&edge[j].c)
					break;
			if(cur[i]!=-1)
			{
				que[top++]=cur[i];
				i=edge[cur[i]].y;
			}
			else
			{
				if(top==0)
					break;
				dep[i]=-1;
				i=edge[que[--top]].x;
			}
		}
	}
	return res;
}
void dfs(int u)
{
	tag[u]=1;
	for(int i=head[u];i!=-1;i=edge[i].nxt)
	{
		if(tag[edge[i].y]==0&&edge[i].c)
			dfs(edge[i].y);
	}
}
int main()
{
	int t,n,m,u,v,k,c,i,j,r;
	int w[N],b[N][35];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		memset(a,0,sizeof(a));
		memset(flag,0,sizeof(flag));
		memset(b,0,sizeof(b));
		memset(w,0,sizeof(w));
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&u,&v);
			a[u][v]=1;a[v][u]=1;
		}
		scanf("%d",&k);
		int bit=0;
		for(i=0;i<k;i++)
		{
			scanf("%d%d",&u,&c);
			w[u]=c; flag[u]=1; j=0;
			while(c>0)
			{
				b[u][j++]=c%2;
				c/=2;
			}
			if(j>bit)
				bit=j;
		}
		for(i=0;i<bit;i++)
		{
			e=0;memset(head,-1,sizeof(head));
			for(j=1;j<=n;j++)
				for(r=1;r<=n;r++)
					if(a[j][r])
						addedge(j,r,1);
			for(j=1;j<=n;j++)
				if(flag[j]&&b[j][i]==1)
					addedge(0,j,inf);
				else if(flag[j])
					addedge(j,n+1,inf);
			int val=maxflow(0,n+1);
			dfs(0);
			for(j=1;j<=n;j++)
				if(!flag[j]&&tag[j])
					b[j][i]=1;
			memset(tag,0,sizeof(tag));
		}
		for(i=1;i<=n;i++)
			if(!flag[i])
			{
				for(j=0;j<bit;j++)
					if(b[i][j])
						w[i]+=(1<<j);
			}
		for(i=1;i<=n;i++)
			printf("%d\n",w[i]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值