POJ-2942 Knights of the Round Table

题意:一些骑士要进行圆桌会议,每桌要坐奇数个人。互相憎恨的骑士不能相邻。现给出骑士之间的憎恨关系(双向),求删去多少人后,能正常开会。

解:将互相不憎恨的骑士连边,也就是补图。注意每个骑士一定不憎恨他自己(离散数学老师:和自己达成和解,这样挺好的)想想下学期就不能听他扯淡了还有点难过,一定不要连自环,在这WA了好几次。因为要坐成一个圆,所以在图上找大于等于3的环。找环用tarjan,但找到了环不能确定它的大小,因为可以偶数环里套奇数环,所以还要判断一下这些点里有没有奇数环,可以用染色,如果一个点将染两种不同的颜色,那就有奇环了。二分图判断也是用的这个方法。

现在来具体实现。首先无向图tarjan找环和有向图是不同的,因为会找到父亲那里,所以要多传一个参数,特判一下(注意这道题没有重边,所以可以直接判)。找环的第一个点,也就是割点的判断条件,dfn[now]<=low[to],然后从栈里把这个环拿出来,判一下奇偶。第一个点不要弹出栈,因为还要找下一条边。

代码:

POJ-2942 Knights of the Round Table
#include <algorithm>
#include <stack>
#include <vector>
#include <stdio.h>
using namespace std;
#define maxx 10005
#define maxn 1005
#define maxm 5000005
#define inf 0x3f3f3f3f
int n,m;
vector<int> e[maxn];
int dfn[maxn]={0},low[maxn]={0};
int cnt=0,vis[maxn]={0};
int cir[maxn],is[maxn];
int bel[maxn],color[maxn],belnum;
int mp[maxn][maxn];
stack<int> s;
int dfs(int now,int col){
    color[now]=col;
    for(int i=0;i<e[now].size();i++){
        int to=e[now][i];
        if(bel[to]!=bel[now])
            continue;
        if(!color[to]&&dfs(to,-col))
            return 1;
        if(color[to]==col)
            return 1;
    }
    return 0;
}
void tarjan(int now,int fa){
    s.push(now);
    vis[now]=1;
    low[now]=dfn[now]=++cnt;
    for(int i=0;i<e[now].size();i++){
        int to=e[now][i];
        if(to==fa)
            continue;
        if(!dfn[to]){
            tarjan(to,now);
            low[now]=min(low[now],low[to]);
            if(dfn[now]<=low[to]){
                int num=0;
                belnum++;
                while(1){
                    int t=s.top();
                    s.pop();
                    vis[t]=0;
                    bel[t]=belnum;
                    cir[++num]=t;
                    if(t==to)
                        break;
                }
                cir[++num]=now;
                bel[now]=belnum;
                memset(color,0,sizeof color);
                if(num>=3&&dfs(now,1)){
                    for(int j=1;j<=num;j++)
                        is[cir[j]]=1;
                }
            }
        }
        else if(vis[to])
            low[now]=min(low[now],dfn[to]);
    }
}
void init(){
    memset(dfn,0,sizeof dfn);
    memset(low,0,sizeof low);
    memset(vis,0,sizeof vis);
    memset(e,0,sizeof e);
    memset(mp,0,sizeof mp);
    memset(is,0,sizeof is);
    memset(bel,0,sizeof bel);
    cnt=0;belnum=0;
    while(!s.empty())
        s.pop();
}
signed main() {
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0)
            break;
        init();
        for(int i=0;i<m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            mp[x][y]=1;
            mp[y][x]=1;
        }
        for(int i=1;i<=n;i++) {
            for (int j = 1; j <= n; j++)
                if (!mp[i][j]&&i!=j)
                    e[i].push_back(j);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i])
                tarjan(i,0);
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(is[i])
                ans++;
        }
        ans=n-ans;
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

上一篇:设计模式---抽象工厂模式


下一篇:Android MVP模式深入实践探索(一),我浪费了自己职业生涯的黄金5年