POJ 2942--Knights of the Round Table(双连通分量)

来源:互联网 发布:逆袭网络剧第三集土豆 编辑:程序博客网 时间:2024/06/08 04:17

题意:有N个骑士,其中某些骑士互相憎恨对方,问要能使奇数个骑士开圆桌会议(憎恨的对方不能在一起)最少需要开除多少人?

题解:注意题意不是要求只开一次使人数达到最大的会议,而是删除那些永远不可能参加圆桌会议的人。

  1. 易知根据输入建立骑士能坐在一起的无向图(不一定连通)。
  2. 求出所有双连通分量,可参考本博对Tarjan论文的翻译。
  3. 在双连通分量里找是否有奇数个点的环(参考CSDN小优),若能找到奇圈,说明双连通分量的点都能参加圆桌会议(可能不是一次会议),对所有人做标记。
  4. 统计不能参加会议的人数输出。
*输入较大,使用读优化&G++时间可极大优化。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define maxN 1005#define maxE 500000int N;char graph[maxN][maxN];         //无向连通图char NoExpelled[maxN];          //驱逐表(1代表能参加会议)char bcc[maxN][maxN];           //双连通分量图char IsInBcc[maxN];            //双连通分量点集char color[maxN];              //染色表int number[maxN];              //点的深搜发现时间int low[maxN];                 //在深搜palm tree(树边和后向边集合)中此点能到达的最早点标号int index;                    //全局发现时间int stackTop;                 //边栈大小struct edge{    short x,y;};edge edgeStack[maxE];bool checkOddCircle(short u){    for(short v = 1;v <= N;v++)    {        if(bcc[u][v])        {            if(color[v] != -1)            {                if(color[u] == color[v])        //找到奇圈则返回真                return true;            }            else            {                color[v] = !color[u];                if(checkOddCircle(v))       //直到找到奇圈才返回,若没找到则要继续遍历双连通分量                    return true;            }        }    }    return false;}int BiConnect(short v,short u)  //u is the father of v in spanning T{    number[v] = low[v] = index++;    for(short w = 1;w <= N;w++)    {        if(w != u&&w != v&&graph[v][w])    //可行边并且不能是其本身以及其父节点        {            edge newEdge;            newEdge.x = v;            newEdge.y = w;            if(!number[w])      //w还没标记,则w将是v的一个子节点            {                edgeStack[stackTop++] = newEdge;       //将边压入栈                BiConnect(w,v);                         //继续深搜                low[v] = min(low[v],low[w]);           //深搜返回后调整low值                if(low[w] >= number[v])                //有双连通分量或者桥边                {                    memset(color,0XFF,sizeof(color));                    memset(bcc,0,sizeof(bcc));                    memset(IsInBcc,0,sizeof(IsInBcc));                    while((--stackTop)&&(edgeStack[(stackTop)].x != newEdge.x||edgeStack[(stackTop)].y != newEdge.y))   //将直到(v,w)的边出栈                    {                        bcc[edgeStack[stackTop].x][edgeStack[stackTop].y] = 1;      //将边保存到双连通分量bcc                        IsInBcc[edgeStack[stackTop].x] = IsInBcc[edgeStack[stackTop].y] = 1;        //记录双连通分量中的点                    }                    bcc[edgeStack[stackTop].x][edgeStack[stackTop].y] = 1;                    IsInBcc[edgeStack[stackTop].x] = IsInBcc[edgeStack[stackTop].y] = 1;                    color[v] = 0;                    if(checkOddCircle(v))                    {                        for(int i = 1;i <= N;i++) //有奇圈则记录奇圈中的点                        {                            if(IsInBcc[i])                            {                                NoExpelled[i] = 1;                            }                        }                    }                }            }            else if(number[w] < number[v])      //(v,w)是后向边,说明有环路            {                edgeStack[stackTop++] = newEdge;                low[v] = min(low[v],number[w]);            }        }    }    return 0;}int init(){    memset(graph,1,sizeof(graph));          //初始化图中所有点均连接    memset(NoExpelled,0,sizeof(NoExpelled));    memset(number,0,sizeof(number));    return 0;}int calcNum(){    int num = 0;    for(short i = 1;i <= N;i++)    {        if(!NoExpelled[i])        {            num++;        }    }    return num;}int main(){    freopen("C:\\Users\\ifuding\\Desktop\\input.txt","r",stdin);    int M;    int x,y;    while(~scanf("%d%d",&N,&M)&&N)    {        init();        while(M--)        {            scanf("%d%d",&x,&y);            graph[x][y] = graph[y][x] = 0;        }        for(int i = 1;i <= N;i++)        {            if(!number[i])            {                index = 1;                stackTop = 0;                BiConnect(i,0);            }        }        printf("%d\n",calcNum());    }    return 0;}


0 0
原创粉丝点击