POJ 1112 Team them up

这学期第一篇博客,啊啊啊,罪过啊,O(∩_∩)O哈哈~

这个题比较复杂:图论结合了简单的DP。

直接还没办法求,需要找到反图,然后才能找到思路!

解题思路:
1.给出有向图,求出无向图,然后根据无向图求出反图
2.DFS求出各一个连通分量,并给每一个连通分量染色
3.DP求出最优状态,并记录路径
详细过程:DP为了求出所有的状态-----也就是在分完第k个连通分量之前(当然是从第1个连通分量开始分的)的所有可能的状态,当分完最后一个连通分量时,就是n个人中所能分出的所有状态!!
即f[i][j]表示未分第k个连通分量时的所有状态!则有:
if(f[i][j]==1 && f[i+cnt[k][0]][j+cnt[k][1]]==0) f[i+cnt[k][0]][j+cnt[k][1]]=1;
if(f[i][j]==1 && f[i+cnt[k][1]][j+cnt[k][0]]==0) f[i+cnt[k][1]][j+cnt[k][0]]=1;
更重要的一点是:得记录路径用pre[i][j]结构体,记录前一个的i,j;记录从前一个状态到这个状态i和j上都加了什么?即记录加的是哪个k的哪一部分(0 & 1)!

#include <iostream>

using namespace std;

const int MAXN=101;

struct Record
{
	int i,j;
	int id,is;
}pre[MAXN][MAXN];

int map[MAXN][MAXN],n;
int dp[MAXN][MAXN];
int cnt[MAXN][2];
int dataPtr[MAXN][2],data[MAXN],next[MAXN],ind;
//int color[MAXN];
int flag[MAXN];


void addedge(int id,int is,int u)
{
	data[ind]=u;
	next[ind]=dataPtr[id][is];
	dataPtr[id][is]=ind;

	ind++;
}

bool DFS(int v,int id,int is)
{
	cnt[id][is]++;
	flag[v]=is;
	addedge(id,is,v);

	for(int u=1;u<=n;u++)
	{
		if(map[v][u])
		{
			if(flag[u]==-1)
			{
				if(DFS(u,id,!is))	return true;
			}		
			else if(flag[v]==flag[u])
				return true;
		}
	}
	
	return false;
}

void solve()
{

	int i , j , k , l , id ;
	cin>>n;

	//求出反图
	memset(map,0,sizeof(map));
	for(i=1;i<=n;i++)
	{
		cin>>j;
	//	while(j) { map[i][j]=1; }	调试①
		while(j) { map[i][j]=1; cin>>j; }
	}

	for(i=1;i<=n;i++)
	{
		for(j=1;j<i;j++)
		{
			if(map[i][j]==1 && map[j][i]==1)
				map[i][j]=map[j][i]=0;
			else	map[i][j]=map[j][i]=1;
		}
	}
	////////////

	///DFS得到连通分量并染色
	memset(flag,-1,sizeof(flag));
//	memset(cnt,0,sizeof(cnt));
//	memset(dp,0,sizeof(dp));
	memset(dataPtr,-1,sizeof(dataPtr)); ind=0;

	//调试②:id没有赋值
	
	id=0;
	for(i=1;i<=n;i++)
	{
		if(flag[i]==-1)
		{
			if(DFS(i,++id,0))
			{
				cout<<"No solution"<<endl;
				return ;
			}
		}
	}

	///DP记录路径并得到结果
	int num=0;	dp[0][0]=1;
	for(k=1;k<=id;k++)
	{
		for(i=0;i<=num;i++)
		{
			j=num-i;
			if(dp[i][j]==1)
			{
				int nexti,nextj;
				for(l=0;l<2;l++)
				{
					nexti=i+cnt[k][l];	nextj=j+cnt[k][!l];
					if(dp[nexti][nextj]==0)
					{
						dp[nexti][nextj]=1;
						pre[nexti][nextj].i=i;
						pre[nexti][nextj].j=j;
						pre[nexti][nextj].id=k;
						pre[nexti][nextj].is=l;
					}
				}
			}
		}
		num+=cnt[k][0]+cnt[k][1];
	}
	for(i=n/2,j=n-i; ;i--,j++)
	{
		if(dp[i][j])	
		{
			break;
		}
	}

	///输出结果
	int ind[2]={0,0};
	cnt[0][0]=i;	cnt[0][1]=j;
	while(i || j)
	{
		int id=pre[i][j].id;
		int is=pre[i][j].is;
		for(int l=0;l<2;l++,is=!is)
		{
			for(int k=dataPtr[id][is];k!=-1;k=next[k])
			{
				cnt[++ind[l]][l]=data[k];
			}
		}
		int tmp=i;
		i=pre[i][j].i;	j=pre[tmp][j].j;
	}

	for(i=0;i<2;i++)
	{
		cout<<cnt[0][i];	
		for(j=1;j<=cnt[0][i];j++)
			cout<<" "<<cnt[j][i];
		cout<<endl;
	}
	
}



int main()
{
	freopen("input.txt","r",stdin);
	
	solve();

	return 0;
}

  

原文地址:https://www.cnblogs.com/fornever/p/2375203.html