• POJ 2942 Knights of the Round Table



    题目描述:
    武士是一个十分吸引人的职业,因此近年来Arthur王国武士的数量得到了空前的增长。武士
    在讨论事情时很容易激动,特别是喝了酒以后。在发现一些不幸的打斗后,Arthur国王要求智者
    Merlin确保将来不会发生武士的打斗。
    Merlin在仔细研究这个问题后,他意识到如果武士围着圆桌坐下,要阻止打斗则必须遵循以
    下两个规则:
    (1) 任何两个互相仇视的武士不能挨着坐,Merlin有一张清单,列出了互相仇视的武士,注意,
    武士是围着圆桌坐下的,每个武士有两个相邻的武士。
    (2) 围着圆桌坐下的武士数量必须为奇数个。这将能保证当武士在争论一些事情时,能通过投
    票的方式解决争端。而如果武士数量为偶数个,则可能会出现赞同和反对的武士数量一样。
    如果以上两个条件满足,Merlin将让这些武士围着圆桌坐下,否则他将取消圆桌会议。如果
    只有一个武士到了,Merlin也将取消会议,因为一个武士无法围着圆桌坐下。Merlin意识到如果
    遵守以上两个规则,可能会使某些武士不可能被安排坐下,一个例子是如果一个武士仇视其他每
    个武士。如果一个武士不可能被安排坐下,他将被从武士名单中剔除掉。你的任务是帮助Merlin
    判断有多少个武士将会被剔除掉。
    输入描述:
    输入文件中包含多个测试数据。每个测试数据第1行为两个整数n和m,1≤n≤1000,1≤
    m≤1000000,n表示武士数目,n个武士编号为1~n,m表示武士相互仇视的对数。接下来有
    m行,描述了相互仇视的每对武士,每行为两个整数k1和k2,表示武士k1和k2相互仇视。
    n = m = 0表示输入结束。
    输出描述:
    对输入文件中的每个测试数据,输出一行,为从名单中被剔除掉的武士数目。


    // 开始理解错题目意思了 一直以为要大家同时坐下去 问有哪些人不能坐 发现自己二了
    // 那样真的怎么动手都不知道
    // 求无向图的双连通分量 (tarjan算法) 并判断奇圈(通过奇偶染色)
    // 主要是只要是点数大于2的非二分图 而且双连通 那么每个点坑定肯定会在某个奇圈里面
    // 首先要理解 点数大于2的非二分图 而且双连通 那么里面肯定含有奇圈 可以用反证法法去理解
    // 那么 某个在这个奇圈外的点 u 与奇圈内的两点u1 u2有2条路径 而且这2条路径完全不重叠,所经过的点都不同 不然就有割点存在了 (由双连通性质决定)
    // 那么 由于 u1 u2两点在奇圈内距离一奇一偶 那么就可让u这个点进入一个奇圈
    // 所以 点数大于2 非二分图 就是可以一起开会的了
    // 还有 二分图不存在奇圈 也可以用反证法去理解

    #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <string.h> using namespace std; #define MOD 1000000007 #define maxn 1000010 #define maxm 1010 struct Edge{ int to; int next; Edge(){}; Edge(int u,int v){to=u;next=v;} }E[maxn]; int V[maxm],num; int pre[maxm]; int dfst,bcc; stack<Edge> S; vector<int> bccno[maxm]; int belong[maxm]; int clor[maxm]; bool ans[maxm]; bool A[maxm][maxm]; void init(){ dfst=0; num=0; bcc=0; while(!S.empty()) S.pop(); memset(V,-1,sizeof(V)); memset(pre,0,sizeof(pre)); memset(ans,0,sizeof(ans)); memset(A,0,sizeof(A)); memset(belong,0,sizeof(belong)); } void add(int u,int v){ E[num].to=v; E[num].next=V[u]; V[u]=num++; E[num].to=u; E[num].next=V[v]; V[v]=num++; } int dfs(int u,int fa){ int lowu; // printf("?"); Edge x; lowu=pre[u]=++dfst; int v,e; for(e=V[u];e!=-1;e=E[e].next){ v=E[e].to; if(!pre[v]){ S.push(Edge(u,v));// 压边进去 int lowv=dfs(v,u); // printf(" %d %d ",u,lowv); lowu=min(lowu,lowv); if(lowv>=pre[u]){ bcc++;bccno[bcc].clear(); for(;;){ // 将形成双连通的部分的点放在一起 x=S.top();S.pop(); // printf("%d %d ",x.to,x.next); if(belong[x.to]!=bcc){bccno[bcc].push_back(x.to);belong[x.to]=bcc; } if(belong[x.next]!=bcc){bccno[bcc].push_back(x.next);belong[x.next]=bcc; } if(x.to==u&&x.next==v) break; } // printf(" u= %d ",bcc); } } else if(v!=fa) lowu=min(lowu,pre[v]); } return lowu; } bool color(int u,int kind){ int e,v; for(e=V[u];e!=-1;e=E[e].next){ v=E[e].to; if(belong[v]!=kind) continue;//printf("kind %d %d ",u,v); if(clor[v]==clor[u]) return false; if(!clor[v]){ clor[v]=3-clor[u]; if(!color(v,kind)) return false; } } return true; } int main() { int n,m; int u,v; int i,j; while(scanf("%d %d",&n,&m),n|m){ init(); for(i=1;i<=m;i++){ scanf("%d %d",&u,&v); A[u][v]=1; A[v][u]=1; } for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) if(!A[i][j]) add(i,j); for(i=1;i<=n;i++) if(!pre[i]) dfs(i,0); for(i=1;i<=bcc;i++){ memset(clor,0,sizeof(clor)); for(j=0;j<bccno[i].size();j++) belong[bccno[i][j]]=i;// 处理 割点 u=bccno[i][0]; clor[u]=1; if(!color(u,i)){// printf("%d %d ",u,i); for(j=0;j<bccno[i].size();j++) ans[bccno[i][j]]=true; } } int out=n; for(i=1;i<=n;i++) if(ans[i]) out--; printf("%d ",out); } return 0; }
  • 相关阅读:
    STL-- vector中resize()和reserve()区别
    计算机网络--网络层
    计算机网络--数据链路层
    算法--排序算法
    数据结构--树--哈夫曼树
    数据结构--树--AVL树
    数据结构--树--二叉查找树
    数据结构--树--红黑树
    深入理解计算机系统读书笔记
    C++面试笔记--字符串
  • 原文地址:https://www.cnblogs.com/372465774y/p/3204211.html
Copyright © 2020-2023  润新知