uva1627

来源:互联网 发布:淘宝店logo生成器 编辑:程序博客网 时间:2024/06/05 17:11

  • 题目大意
  • 思路
  • 代码
  • Hit

题目大意

传送门

有n个人,把他们分成非空的两组,使得每个人都被分到一组,并且同组的人要相互认识。要求两组的人数要尽量接近。多解的时候输出任意方案,无解时候输出No Solution。

思路

组的编号为0和1。因为同组的人必须相互认识,如果已知某个人在组0,那么不认识此人的就必须在组1

让不认识关系组成一张图。

例如:
1 认识 2 3 5
2 认识 1 3 4 5
3 认识 1 2 5
4 认识 1 2 3
5 认识 1 2 3 4

那么不认识关系就是

2

4-1 4-3 4-5

代码

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>using namespace std;#define maxn 205int G[maxn][maxn];//原关系图vector<int> Ng[maxn];//不认识关系图vector<int> C[4];//将每一组染色的数目int color[maxn];//判断是否染色int diff_C[maxn];vector<int> list_color0[maxn];vector<int> list_color2[maxn];int CaseNum;int N;int dp[maxn][maxn*2];int cnt = 0;int cnt_color[3];//dfs过程,给点染色,并且bool dfs(int u,int father){    for(int i = 0 ; i<Ng[u].size(); i++)    {        int v = Ng[u][i];        if(v!=father)        {            if(color[v] == 0)//v没有染色            {                color[v] = -color[u];//把与u相连的点v染色成相反的颜色                cnt_color[color[v]+1]++;//计数color[u]的点                if(color[v] + 1 == 0 ) list_color0[C[0].size()].push_back(v);                if(color[v] + 1 == 2 ) list_color2[C[0].size()].push_back(v);                if(!dfs(v,u)) return false;            }            else if(color[v] == -color[u]){//已经染色  但是颜色正确            }            else//u已经染色  不存在这样的情况                return false;        }    }    return true;}//输出结果void print_ans(int ans){    vector<int> team0,team2;    for(int i = C[0].size()-1; i >= 0; i--)    {        int t = 0;        if(dp[i][ans - diff_C[i] + N] == 1)        {            t = 0;            ans -=diff_C[i];        }        else        {            t = 1;            ans += diff_C[i];        }        if(t==1)        {            for(int j =0; j<list_color0[i].size(); j++)                team0.push_back(list_color0[i][j]);            for(int j =0; j<list_color2[i].size(); j++)                team2.push_back(list_color2[i][j]);        }        else        {            for(int j =0; j<list_color0[i].size(); j++)                team2.push_back(list_color0[i][j]);            for(int j =0; j<list_color2[i].size(); j++)                team0.push_back(list_color2[i][j]);        }    }    printf("%d",team0.size());    for(int j=0; j<team0.size(); j++)        printf(" %d",team0[j]);    printf("\n");    printf("%d",team2.size());    for(int j=0; j<team2.size(); j++)        printf(" %d",team2[j]);    printf("\n");}int main(){    scanf("%d",&CaseNum);    while(CaseNum--)    {        memset(G,0,sizeof(G));        scanf("%d",&N);        for(int i =1; i<=N; i++)        {            int v;            while(scanf("%d",&v)&&v) G[i][v] = 1;            Ng[i].clear();        }        //构成不认识关系图        for(int i = 1; i<=N; i++)        {            for(int j = i+1; j<=N; j++)            {                if((!G[i][j])||(!G[j][i]))                {                    Ng[i].push_back(j);                    Ng[j].push_back(i);                }            }        }/*        for(int i = 1;i<=N;i++){            for(int j = 0; j<Ng[i].size();j++){                printf("%d %d\n",i,Ng[i][j]);            }            printf("\n");        }*/        //        cnt = 0;        cnt_color[0] = 0;        cnt_color[2] = 0;        C[0].clear();        C[1].clear();        for(int i = 0; i<N; i++)        {            list_color0[i].clear();            list_color2[i].clear();        }        bool flag = true;        for(int i =1 ; i<= N; i++) color[i] = 0; //置为没有染色        for(int i =1 ; i<= N; i++)        {            if(color[i] == 0) //若当前点没有染色            {                color[i] = -1;//将color[i]染色为-1                cnt_color[-1+1]++;//颜色-1的总数++                list_color0[C[0].size()].push_back(i);                flag = dfs(i,0);                if(flag == false) break;                C[0].push_back(cnt_color[0]);                C[1].push_back(cnt_color[2]);                //printf("%d %d %d\n",i,cnt_color[0],cnt_color[2]);                cnt_color[0] = 0;                cnt_color[2] = 0;            }        }        if(flag == false)        {            printf("No solution\n");            if(CaseNum) cout<<endl;            continue;        }        for(int i = 0; i< C[0].size(); i++)        {            //printf("%d %d\n",C[0][i],C[1][i]);            diff_C[i] = C[0][i]-C[1][i];        }/*        for(int i=0; i<C[0].size(); i++)        {            for(int j = 0; j< list_color0[i].size(); j++)            {                printf("color0   %d \n",list_color0[i][j]);            }            for(int j = 0; j< list_color2[i].size(); j++)            {                printf("color2   %d \n",list_color2[i][j]);            }        }*/        //使用dp算得每一组中的染色格子怎么放:        memset(dp,0,sizeof(dp));        dp[0][0+N] = 1;        for(int i = 0; i<C[0].size(); i++)        {            for(int j = -N; j<=N; j++)            {                if(dp[i][j+N])                {                    dp[i+1][j+diff_C[i] + N] = 1;                    dp[i+1][j-diff_C[i] + N] = 1;                }            }        }        for(int i = 0; i<=N; i++)        {            if(dp[C[0].size()][i+N])            {                print_ans(i);                break;            }            if(dp[C[0].size()][-i+N])            {                print_ans(i);                break;            }        }        if(CaseNum) cout<<endl;    }    return 0;}

Hit

判断能否有解的时候,我出现了两个错误:

  1. 之前写的是如果下一个着色器已经有颜色,直接return false,这是个错误的写法,因为不认识关系是个四边形的环的时候,这种情况return false,但是其实是正确的。
  2. 还有一个dfs的地方写错,因为当下一个结点false的时候,其实整个dfs过程都是false。所以应该这样写:

    if(!dfs(v,u)) return false;
原创粉丝点击