【bzoj 3495】PA2010 Riddle

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)$

 

 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 }
View Code

 

posted @ 2018-04-25 10:07  Zsnuo  阅读(198)  评论(0编辑  收藏  举报