uva 1627 动态规划,01背包,二分图染色

主要思路是大白书上的,利用二分图染色判断是不是no solution,二分图染色的那个函数就是judge和dfs,然后dp[i][j]==1表示把第i个二分图的一部分加入第一队后,第一队有j人,dp[i][j] == 0 表示把第i个联通块加入第一队后,第一队的人数不可能是j人,显然,设有m个联通块,n个人,那么如果有最优解,最优解就是dp[m][j]中j最接近n/2的。way[][]数组用来保存第一队的路径。       

状态转移方程:

memset(dp, 0, sizeof(dp));

dp[0][0] = 1;

if(dp[i-1][j])     dp[i][j+team[i][0].size()] = dp[i][j+tem[i][1].size()] = 1.

#include <cstdio>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;

vector<int> G[10000];
int rel[5000][5000];
int col[10000];
int diff[1000];
int dp[5000][5000];
int way[5000][5000];
int way2[5000][5000];
vector<int> team[10000][2];
int k = 1;
int n;

void print(int p)
{
	int u = k-1;
	printf("%d",p);
	int aim = p;
	while(aim)
	{
		int t = way[u][aim];
		for(int i = 0; i < team[u][t].size(); i++)
			printf(" %d",team[u][t][i]);
		aim -= team[u][t].size();
		u--;
	}
	printf("\n");
	printf("%d",n-p);
	aim = n-p;
	u = k-1;
	
	while(aim)
	{
		int t = !way[u][p];
		for(int i = 0; i < team[u][t].size(); i++)
			printf(" %d",team[u][t][i]);
		aim -= team[u][t].size();
		p -= team[u][!t].size();
		u--;
	}
	printf("\n");
	
}

bool dfs(int i, int color)
{
	col[i] = color;
	team[k][color].push_back(i);
	for(int j = 1; j <= n; j++)
	{
		if(i != j && !(rel[i][j] && rel[j][i]))
		{
			if(col[j] >= 0 && col[i] == col[j])	 return false;
			if(col[j] == -1 && !dfs(j, !color))	 return false;
		}
	}
	return true;
}
	
bool judge()
{
	for(int i = 1; i <= n; i++)
	{
		if(col[i] == -1){
			team[k][0].clear();
			team[k][1].clear();
			if(!dfs(i, 0))	return false;
			k++;
		}
	}
	return true;
}

void dynamic()
{
	memset(dp, 0, sizeof(dp));
	dp[0][0] = 1;
	for(int i = 1; i < k; i++)
	{
		for(int j = 0; j <= n; j++)
		if(dp[i-1][j])
		{
			if(dp[i][j + team[i][0].size()] == 0){
			dp[i][j + team[i][0].size()] = 1;
			way[i][j + team[i][0].size()] = 0;
			}
			if(dp[i][j + team[i][1].size()] == 0){
				dp[i][j + team[i][1].size()] = 1;
				way[i][j + team[i][1].size()] = 1;
			}
		}
	}
	int p = 0;
	int m = n/2;
	while(1)
	{
		if(dp[k-1][m+p] == 1)
		{
			print(m+p);
			break;
		}
		else
		if(dp[k-1][m-p] == 1)
		{
			print(m-p);
			break;
		}
		p++;
	}

}
		
		
		
int main()
{
	//freopen("ztest.txt","r",stdin);
	//freopen("zans.txt","w",stdout);
	int t;
	int temp;
	scanf("%d",&t);
	int h = 1;
	while(t--)
	{
		if(h)
			h = 0;
		else
			printf("\n");
		scanf("t=  %d\n",t);
		k = 1;
		memset(rel, 0, sizeof(rel));
		memset(col, -1, sizeof(col));
		memset(diff, 0, sizeof(diff));
		memset(way, -1, sizeof(way));
		memset(way2, -1, sizeof(way2));
		scanf("%d", &n);
		for(int i = 1; i <= n; i++)
			G[i].clear();
		for(int i = 1; i <= n; i++)
			while(scanf("%d",&temp) && temp)
				rel[i][temp] = 1;
		for(int i = 1; i < n; i++)
		for(int j = i + 1; j <= n; j++)
			if(!(rel[i][j] && rel[j][i]))
			{
				G[i].push_back(j);
				G[j].push_back(i);
			}
		if(!judge())
			printf("No solution\n");
		else
			dynamic();
	}
	return 0;
}
		
		
		
		
		
		
		
		
		
		

猜你喜欢

转载自blog.csdn.net/wukongakk/article/details/80968668