模板
void addedge(int u,int v){ g[u].pb(v); rg[v].pb(u); } void dfs(int u){ vis[u]=1; for(int i=0;i<g[u].size();i++) if(!vis[g[u][i]]) dfs(g[u][i]); cb.pb(u); } void rdfs(int u,int k){ vis[u]=1; cmp[u]=k; for(int i=0;i<rg[u].size();i++) if(!vis[rg[u][i]]) rdfs(rg[u][i],k); } int n,m; int scc(){///返回强连通分量的数量 for(int i=0;i<2*n;i++) if(!vis[i]) dfs(i); int k=0; memset(vis,0,sizeof(vis)); for(int i=cb.size()-1;i>=0;i--){ if(!vis[cb[i]]) rdfs(cb[i],k++); } return k; }
提:http://acm.hdu.edu.cn/showproblem.php?pid=3062
题目思路:
对于这类问题一般的解法为将每个点分为 x 和 x' 分别表示每组当中的两种状态,这里表示丈夫和妻子,然后更具定义我们建图,如果 A和B有矛盾则选A必选B',选B必选A' ,所以我们对该图缩点,如果A和A'属于同一个环当中则说明选A必选A',所以不存在,否则就存在
#include<vector> #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define pb push_back const int M=5000; vector<int>g[M]; int low[M],dfn[M],sta[M],vis[M],cmp[M]; int tot,cnt,top; void tarjan(int u){ low[u]=dfn[u]=++cnt; sta[++top]=u; vis[u]=1; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ tot++; cmp[u]=tot; vis[u]=0; while(sta[top]!=u){ cmp[sta[top]]=tot; vis[sta[top--]]=0; } top--; } } int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ for(int i=0;i<=2*n;i++) g[i].clear(),low[i]=dfn[i]=cmp[i]=vis[i]=sta[i]=0; top=cnt=tot=0; while(m--){ int a1,a2,c1,c2; scanf("%d%d%d%d",&a1,&a2,&c1,&c2); int a = a1*2+c1; int b = a2*2+c2; g[a].pb(b^1); // cout<<u<<"----"<<2*a2+(1-c2)<<endl; // g[2*a2+(1-c2)].pb(u); g[b].pb(a^1); // cout<<v<<"----"<<2*a1+(1-c1)<<endl; // g[2*a1+(1-c1)].pb(v); } for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i); int flag=1; for(int i=0;i<n;i++){ if(cmp[2*i]==cmp[2*i+1]){ flag=0; break; } } if(flag) puts("YES"); else puts("NO"); } return 0; }
例题:输出满足条件的方案是什么
题:http://acm.hdu.edu.cn/showproblem.php?pid=1814
把所有能到达的点标记一下,顺便判断一下和之前有没有矛盾,有矛盾的话所有被标记的点又要重新标记回去。
#include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; #define pb push_back const int M=2e4+4; vector<int>g[M]; int vis[M],s[M],tot,n; bool dfs(int u){ if(vis[u]) return true; if(vis[u^1]) return false; vis[u]=1; s[tot++]=u; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!dfs(v)) return false; } return true; } bool solve(){ for(int i=0;i<2*n;i+=2){ if(vis[i]||vis[i^1]) continue; tot=0;///相当于缩点过程 if(!dfs(i)){ while(tot) vis[s[--tot]]=0; if(!dfs(i^1)) return false; } } return true; } int main(){ int m; while(~scanf("%d%d",&n,&m)){ for(int i=0;i<=2*n;i++) g[i].clear(),vis[i]=0; while(m--){ int u,v; scanf("%d%d",&u,&v); u--,v--; g[u].pb(v^1); g[v].pb(u^1); } if(solve()){ for(int i=0;i<2*n;i++) if(vis[i]) printf("%d ",i+1); } else puts("NIE"); } return 0; }
题:https://codeforces.com/problemset/problem/468/B
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define pb push_back const int M=2e5+5; struct node{ int val,id; bool operator<(const node &b)const{ return val<b.val; } }a[M]; vector<int>g[M],rg[M],newg; int vis[M],cmp[M]; void addedge(int u,int v){ g[u].pb(v); rg[v].pb(u); } void dfs(int u){ vis[u]=1; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!vis[v]) dfs(v); } newg.pb(u); } void rdfs(int u,int k){ vis[u]=1; cmp[u]=k; for(int i=0;i<rg[u].size();i++){ int v=rg[u][i]; if(!vis[v]) rdfs(v,k); } } int n,A,B; int scc(){ for(int i=0;i<2*n;i++) if(!vis[i]) dfs(i); memset(vis,0,sizeof(vis)); int k=0; for(int i=newg.size()-1;i>=0;i--){ int v=newg[i]; if(!vis[v]) rdfs(v,k++); } } int main(){ scanf("%d%d%d",&n,&A,&B); for(int i=0;i<n;i++) scanf("%d",&a[i].val),a[i].id=i; sort(a,a+n); for(int i=0;i<n;i++){ int pos=lower_bound(a,a+n,node{A-a[i].val,0})-a; if(pos!=n&&a[pos].val==A-a[i].val){ addedge(a[i].id,a[pos].id); addedge(a[pos].id+n,a[i].id+n); } else{ addedge(a[i].id,a[i].id+n); } pos=lower_bound(a,a+n,node{B-a[i].val,0})-a; if(pos!=n&&a[pos].val==B-a[i].val){ addedge(a[i].id,a[pos].id); addedge(a[pos].id+n,a[i].id+n); } else{ addedge(a[i].id+n,a[i].id);///这一步与上面处理相反是为了在输出归属方案时区别开来 } // cout<<pos<<endl; } int k=scc(); for(int i=0;i<n;i++){ if(cmp[i]==cmp[i+n]) return puts("NO"),0; } puts("YES"); for(int i=0;i<n;i++){ if(cmp[i]>cmp[i+n]) printf("0 "); else printf("1 "); } return 0; }
题:http://poj.org/problem?id=3207
题意:平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,
比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。
给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,
使这些边都不相交。
#include<vector> #include<cstring> #include<algorithm> #include<cstdio> #include<iostream> using namespace std; typedef long long ll; #define pb push_back const int M=2003; vector<int>g[M],rg[M],cb; int vis[M],cmp[M]; void addedge(int u,int v){ g[u].pb(v); rg[v].pb(u); } void dfs(int u){ vis[u]=1; for(int i=0;i<g[u].size();i++) if(!vis[g[u][i]]) dfs(g[u][i]); cb.pb(u); } void rdfs(int u,int k){ vis[u]=1; cmp[u]=k; for(int i=0;i<rg[u].size();i++) if(!vis[rg[u][i]]) rdfs(rg[u][i],k); } int n,m; int scc(){ for(int i=0;i<2*n;i++) if(!vis[i]) dfs(i); int k=0; memset(vis,0,sizeof(vis)); for(int i=cb.size()-1;i>=0;i--){ if(!vis[cb[i]]) rdfs(cb[i],k++); } return k; } int a[M]; vector<int>fuck; int main(){ memset(a,-1,sizeof(a)); scanf("%d%d",&n,&m); for(int u,v,i=1;i<=m;i++){ scanf("%d%d",&u,&v); a[u]=v; a[v]=u; fuck.pb(u); fuck.pb(v); } sort(fuck.begin(),fuck.end()); for(int i=0;i<fuck.size();i++){ for(int j=i+1;j<fuck.size();j++){ int l=min(fuck[i],a[fuck[i]]),r=max(fuck[i],a[fuck[i]]); int L=min(fuck[j],a[fuck[j]]),R=max(fuck[j],a[fuck[j]]); if((l<L&&L<r&&R>r)||l<R&&R<r&&l>L){///代表这俩条线不能同时在圆内或圆外,即俩者矛盾 addedge(fuck[i],fuck[j]+n); addedge(fuck[j],fuck[i]+n); addedge(fuck[i]+n,fuck[j]); addedge(fuck[j]+n,fuck[i]); } } } int k=scc(); for(int i=0;i<fuck.size();i++){ int v=fuck[i]; if(cmp[v]==cmp[v+n]) return puts("the evil panda is lying again"),0; } puts("panda is telling the truth..."); return 0; }