标签:
Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 10804 | Accepted: 3553 |
Description
Input
Output
Sample Input
5 5 1 4 1 5 2 5 3 4 4 5 0 0
Sample Output
2
题意:一群骑士要召开圆桌会议,坐在圆桌上的人都有两个邻居
满足两个要求:每个人与身边的邻居都不能有矛盾,且围坐的人数必须是奇数
题目给出m对矛盾关系,问有多少人一定是不能参加会议的
分析:
1.首先做补图,把题中给出的边舍去,把没有给出的边建图
2.然后在图中找奇数环,求点的双连通块
3.在双连通块中找奇数点的环,如果一个联通块中存在一个奇数环,那么该连通块中的每个人都有可能成为一个奇数环中的一员,此时把可能成为一员的人标记
4.找奇数环实际上就是判断该联通块是否是二分图,即用黑白交叉染色法判断,如果某条边的两个端点有相同的颜色,就存在了奇数环
程序:
1 #include"stdio.h" 2 #include"string.h" 3 #include"stdlib.h" 4 #include"algorithm" 5 #include"queue" 6 #include"math.h" 7 #include"iostream" 8 #include"vector" 9 #define M 1009 10 #define inf 0x3f3f3f3f 11 #define eps 1e-9 12 #define PI acos(-1.0) 13 #include"map" 14 #include"vector" 15 #include"set" 16 #include"string" 17 #include"stack" 18 #define LL __int64 19 using namespace std; 20 struct node 21 { 22 int u,v,next; 23 }edge[M*M*2]; 24 int t,head[M],dfn[M],low[M],cut[M],belong[M*M*2],use[M],color[M],exist[M]; 25 int indx,num; 26 int G[M][M]; 27 stack<int>q; 28 vector<int>bian[M]; 29 void init() 30 { 31 t=0; 32 memset(head,-1,sizeof(head)); 33 } 34 void add(int u,int v) 35 { 36 edge[t].u=u; 37 edge[t].v=v; 38 edge[t].next=head[u]; 39 head[u]=t++; 40 } 41 int dfs(int u)//交叉染色判断二分图 42 { 43 for(int i=0;i<(int)bian[u].size();i++) 44 { 45 int v=bian[u][i]; 46 if(color[v]==-1) 47 { 48 color[v]=color[u]^1; 49 int tt=dfs(v); 50 if(tt) 51 return 1; 52 } 53 else if(color[v]==color[u]) 54 return 1; 55 } 56 return 0; 57 } 58 void tarjan(int u,int fa,int id) 59 { 60 dfn[u]=low[u]=++indx; 61 for(int i=head[u];~i;i=edge[i].next) 62 { 63 int v=edge[i].v; 64 if(i==(id^1))continue; 65 if(!dfn[v]) 66 { 67 q.push(i);//把边入栈 68 tarjan(v,u,i); 69 low[u]=min(low[u],low[v]); 70 if(dfn[u]<=low[v])//求割点 71 { 72 cut[u]++; 73 int x; 74 num++; 75 int cnt=0; 76 map<int,int>mp; 77 do//当搜到一个割点u的时候把栈中边出栈,所有出栈的边都属于一个点双连通块 78 { 79 x=q.top(); 80 q.pop(); 81 belong[x]=belong[x^1]=num; 82 bian[edge[x].u].push_back(edge[x].v);//建立连通块联通图 83 bian[edge[x].v].push_back(edge[x].u); 84 if(!mp[edge[x].u])//离散化点 85 { 86 mp[edge[x].u]=1; 87 use[cnt++]=edge[x].u; 88 } 89 if(!mp[edge[x].v]) 90 { 91 mp[edge[x].v]=1; 92 use[cnt++]=edge[x].v; 93 } 94 95 }while(i!=x); 96 color[use[0]]=1; 97 if(dfs(use[0]))//如果存在奇数环,把点标记 98 { 99 for(int i=0;i<cnt;i++) 100 exist[use[i]]=1; 101 } 102 for(int i=0;i<cnt;i++)//清理初始化边和color标记 103 { 104 bian[use[i]].clear(); 105 color[use[i]]=-1; 106 } 107 } 108 } 109 else if(low[u]>dfn[v]) 110 { 111 low[u]=dfn[v]; 112 q.push(i);//把边入栈 113 } 114 } 115 if(fa<0) 116 cut[u]--; 117 } 118 int slove(int n) 119 { 120 for(int i=0;i<=n;i++) 121 bian[i].clear(); 122 indx=num=0; 123 memset(cut,0,sizeof(cut)); 124 memset(dfn,0,sizeof(dfn)); 125 memset(use,0,sizeof(use)); 126 memset(color,-1,sizeof(color)); 127 memset(exist,0,sizeof(exist)); 128 for(int i=1;i<=n;i++) 129 { 130 if(!dfn[i]) 131 tarjan(i,-1,-1); 132 } 133 int ans=0; 134 for(int i=1;i<=n;i++) 135 { 136 if(!exist[i]) 137 ans++; 138 } 139 return ans; 140 } 141 int main() 142 { 143 int n,m; 144 while(scanf("%d%d",&n,&m),m||n) 145 { 146 init(); 147 memset(G,0,sizeof(G)); 148 for(int i=1;i<=m;i++) 149 { 150 int a,b; 151 scanf("%d%d",&a,&b); 152 G[a][b]=G[b][a]=1; 153 } 154 for(int i=1;i<=n;i++) 155 { 156 for(int j=i+1;j<=n;j++) 157 { 158 if(!G[i][j]) 159 { 160 add(i,j); 161 add(j,i); 162 } 163 } 164 } 165 int ans=slove(n); 166 printf("%d\n",ans); 167 } 168 return 0; 169 }
标签:
原文地址:http://www.cnblogs.com/mypsq/p/4713807.html