由于互相憎恨的骑士不能相邻,把可以相邻的骑士连上无向边,会议要求是奇数,问题就是求不再任意一个简单奇圈上的结点个数。
tarjan直接套以前写的,结果就错了,要特别注意把边加入栈的时间。。。还不是很理解这个算法
#include<bits/stdc++.h> using namespace std; #define bug(x) cout<<#x<<‘=‘<<x<<endl; const int maxv = 1000+5; const int maxe = maxv*maxv;//开小 int dfn[maxv],low[maxv],bccno[maxv],dfs_clock,bcc_cnt; bool iscut[maxv]; vector<int> bcc[maxv]; int head[maxv],fro[maxe],to[maxe],nxt[maxe],ecnt; int edges[maxe],top; void addEdge(int u,int v) { fro[ecnt] = u; to[ecnt] = v; nxt[ecnt] = head[u]; head[u] = ecnt++; } void tarjan(int u,int fa) { dfn[u] = low[u] = ++dfs_clock; for(int i = head[u]; ~i; i = nxt[i]){ int v = to[i]; if(!dfn[v]){ edges[++top] = i; tarjan(v,i); low[u] = min(low[v],low[u]); if(low[u] >= dfn[u]){ iscut[u] = true; bcc_cnt++; bcc[bcc_cnt].clear(); //bcc从1开始 int U,V; do{ int e = edges[top--]; U = fro[e], V = to[e]; if(bccno[U] != bcc_cnt) { bcc[bcc_cnt].push_back(U); bccno[U]=bcc_cnt; } if(bccno[V] != bcc_cnt) { bcc[bcc_cnt].push_back(V); bccno[V]=bcc_cnt; } }while(U!=u||V!=v); } }else if((i^1) != fa && dfn[v] < dfn[u] ){ low[u] = min(low[u],dfn[v]); edges[++top] = i; }// == 比 ^优先级高!第二个条件少了会WA是什么原因 } } void find_bcc(int n) { top = 0; memset(dfn ,0,sizeof(dfn)); memset(iscut, 0,sizeof(iscut)); memset(bccno, 0,sizeof(bccno)); dfs_clock = bcc_cnt = 0; for(int i = 0; i < n; i++) { if(!dfn[i]) { tarjan(i,-1); iscut[i] = ~nxt[head[i]];// !(nxt[head[i]] == -1);//树根特判,如果只有一个子结点false } } } int color[maxv]; bool bipartite(int u, int b) { for(int i = head[u]; ~i; i = nxt[i]){ int v = to[i]; if(bccno[v] != b) continue; if(color[v] == color[u]) return false; if(!color[v]){ color[v] = 3 - color[u]; if(!bipartite(v,b)) return false; } } return true; } bool hate[maxv][maxv]; bool inOdd[maxv]; int main() { //freopen("in.txt","r",stdin); int n,m; while(~scanf("%d%d",&n,&m)&&(n||m)){ memset(hate,0,sizeof(hate)); while(m--){ int u,v; scanf("%d%d",&u,&v); u--,v--; hate[u][v] = hate[v][u] = true; } memset(head,-1,sizeof(head)); ecnt = 0; for(int i = 0; i < n; i++) for(int j = i+1; j < n; j++) if(!hate[i][j]){ addEdge(i,j); addEdge(j,i); } find_bcc(n); // bug(bcc_cnt); memset(inOdd,0,sizeof(inOdd)); for(int i = 1; i <= bcc_cnt; i++){ memset(color,0,sizeof(color)); for(int j = 0; j < bcc[i].size(); j++) bccno[bcc[i][j]] = i; //割点,属于多个连通分量,因此特殊处理 int u = bcc[i][0]; color[u] = 1; if(!bipartite(u,i)){ for(int j = 0; j < bcc[i].size(); j++) inOdd[bcc[i][j]] = true; } } int ans = n; for(int i= 0; i < n; i++) if(inOdd[i]) ans--; printf("%d\n",ans); } return 0; }
时间: 2024-11-05 13:41:51