这学期第一篇博客,啊啊啊,罪过啊,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; }