Description
有n个城镇被分成了k个郡,有m条连接城镇的无向边。要求给每个郡选择一个城镇作为首都,满足每条边至少有一个端点是首都。
Input
第一行有三个整数,城镇数n(1<=n<=10^6),边数m(0<=m<=10^6),郡数k(1<=k<=n)。
接下来m行,每行有两个整数ai和bi(ai≠bi),表示有一条无向边连接城镇ai和bi。
接下来k行,第j行以一个整数wj开头,后面是wj个整数,表示第j个郡包含的城镇。
Output
若有解输出TAK,否则输出NIE。
每个点 $x$ 拆成两对点,$x$ 代表选择 $x$ 为首都,$x+n$ 表示不选择 $x$ 为首都,$x+2n$ 表示 $x$ 的前缀已包含首都,$x+3n$表示 $x$ 的前缀不包含首都。
对于每一条原图中无向边 $(x,y)$ ,因为至少有一个端点为首都,连边 $(x+n,y)$ ,$(y+n,x)$。
对于每一个点 $x$ ,连边 $(x,x+2n)$ ,$(x+3n,x+n)$。
对于每一个点 $x$ 与它的上一个点 $last$ ,连边方式如下:$(last+2n,x+2n)$,$(x+3n,last+3n)$,$(last+2n,x+n)$,$(x,last+3n)$。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 using namespace std; 6 const int N=4e6+5; 7 int n,m,k,cnt,x,y,last,tim,top,color; 8 int first[N],dfn[N],low[N],sta[N],c[N]; 9 bool vis[N]; 10 struct edge{int to,next;}e[N*3]; 11 void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;} 12 int read() 13 { 14 int x=0,f=1;char c=getchar(); 15 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 16 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 17 return x*f; 18 } 19 void tarjan(int x) 20 { 21 low[x]=dfn[x]=++tim; 22 sta[++top]=x;vis[x]=true; 23 for(int i=first[x];i;i=e[i].next) 24 { 25 int to=e[i].to; 26 if(!dfn[to])tarjan(to),low[x]=min(low[x],low[to]=min(low[x],low[to])); 27 else if(vis[to])low[x]=min(low[x],dfn[to]); 28 } 29 if(low[x]==dfn[x]) 30 { 31 color++; 32 while(sta[top]!=x)vis[sta[top]]=false,c[sta[top--]]=color; 33 vis[x]=false;c[x]=color;top--; 34 } 35 } 36 bool check() 37 { 38 for(int i=1;i<=n;i++) 39 if(c[i]==c[i+n]||c[i+2*n]==c[i+3*n])return false; 40 return true; 41 } 42 int main() 43 { 44 n=read();m=read();k=read(); 45 for(int i=1;i<=m;i++) 46 { 47 x=read();y=read(); 48 ins(x+n,y);ins(y+n,x); 49 } 50 for(int i=1;i<=k;i++) 51 { 52 x=read();last=0; 53 for(int j=1;j<=x;j++) 54 { 55 y=read(); 56 ins(y,y+2*n);ins(y+3*n,y+n); 57 if(last) 58 { 59 ins(last+2*n,y+2*n); 60 ins(y+3*n,last+3*n); 61 ins(last+2*n,y+n); 62 ins(y,last+3*n); 63 } 64 last=y; 65 } 66 } 67 for(int i=1;i<=4*n;i++)if(!dfn[i])tarjan(i); 68 if(check())printf("TAK"); 69 else printf("NIE"); 70 return 0; 71 }