codeforces #290 div1 C(最大流,输出解)
2015-02-06 00:44:25
思路:神奇的网络流题...
之前cf某题也是类似的网络流,不过是相加为奇数的情况。
这一题要求相加为素数,其实也是同理的,素数必定为奇数嘛... 那么只要将奇数放在左列,偶数放在右列,然后加一个源点和所有左列点相连,容量为2,加一个汇点和所有右列点相连容量为2... 再考虑对每一个左列点,扫一遍所有右列点,如果相加为素数那么建边,容量为1。
这么建图的原因:每个奇数一定相邻2个偶数,每个偶数一定相邻2个奇数,这样才有可能满足题意。每个奇数与两个偶数产生1的流量,与源点和汇点各产生2的流量。
最后,要输出解。
考虑:跑完最大流后,最大流的边容量都变成0了,反向边存的是最大流...
所以我们找到每条容量为0的边,重新建图,对所有未标记的点跑一遍Dfs,Dfs过程中标记点已经遍历即可。
注意:由于题目每个数 <= 10^4,但是有数相加的情况,所以如果是用素数表来判断的话,数组范围要开到2*10^4!!
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define REV(i,n) for(int i=(n-1);i>=0;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define MP(a,b) make_pair(a,b) 21 22 typedef long long ll; 23 typedef pair<int,int> pii; 24 const int INF = (1 << 30) - 1; 25 const int MAXN = 210; 26 const int MAXM = 50010; 27 28 int pm[200010]; 29 30 void Pre(){ 31 FOR(i,2,20000) if(!pm[i]){ 32 for(int j = i + i; j <= 20000; j += i) 33 pm[j] = 1; 34 } 35 } 36 37 struct Max_flow{ 38 int first[MAXN],next[MAXM],ver[MAXM],cp[MAXM],ecnt; 39 int lev[MAXN],st,ed; 40 void Init(){ 41 MEM(first,-1); 42 ecnt = 0; 43 } 44 void Add_edge(int u,int v,int c){ 45 next[ecnt] = first[u]; 46 ver[ecnt] = v,cp[ecnt] = c; 47 first[u] = ecnt++; 48 //opposite 49 next[ecnt] = first[v]; 50 ver[ecnt] = u,cp[ecnt] = 0; 51 first[v] = ecnt++; 52 } 53 bool Bfs(){ 54 queue<int> Q; 55 MEM(lev,-1); 56 Q.push(st); 57 lev[st] = 0; 58 while(!Q.empty()){ 59 int now = Q.front(); Q.pop(); 60 for(int i = first[now]; ~i; i = next[i]){ 61 int v = ver[i]; 62 if(lev[v] < 0 && cp[i] > 0){ 63 lev[v] = lev[now] + 1; 64 Q.push(v); 65 } 66 } 67 } 68 return lev[ed] != -1; 69 } 70 int Dfs(int p,int minf){ 71 if(p == ed) return minf; 72 for(int i = first[p]; ~i; i = next[i]){ 73 int v = ver[i]; 74 if(lev[v] > lev[p] && cp[i] > 0){ 75 int d = Dfs(v,min(cp[i],minf)); 76 if(d > 0){ 77 cp[i] -= d; 78 cp[i ^ 1] += d; 79 return d; 80 } 81 } 82 } 83 return 0; 84 } 85 int Dinic(){ 86 int max_flow = 0,pl; 87 while(Bfs()){ 88 while((pl = Dfs(st,INF)) > 0) 89 max_flow += pl; 90 } 91 return max_flow; 92 } 93 }; 94 95 int n; 96 int val[MAXN],cnt[2]; 97 int first[MAXN],ecnt; 98 vector< vector<int> > ans; 99 vector<int> res; 100 int vis[MAXN]; 101 102 struct edge{ 103 int v,next; 104 }e[MAXM]; 105 106 void Add_edge(int u,int v){ 107 e[++ecnt].next = first[u]; 108 e[ecnt].v = v; 109 first[u] = ecnt; 110 } 111 112 void Dfs(int p){ 113 vis[p] = 1; 114 res.push_back(p); 115 for(int i = first[p]; ~i; i = e[i].next){ 116 int v = e[i].v; 117 if(!vis[v]) Dfs(v); 118 } 119 } 120 121 int main(){ 122 Pre(); 123 Max_flow MF; MF.Init(); 124 scanf("%d",&n); 125 FOR(i,1,n){ 126 scanf("%d",&val[i]); 127 int id = val[i] & 1; 128 cnt[id]++; 129 if(id) MF.Add_edge(0,i,2); //源点和奇数连边 130 else MF.Add_edge(i,n + 1,2); //汇点和偶数连边 131 } 132 if(cnt[0] != cnt[1]){ 133 printf("Impossible\n"); 134 return 0; 135 } 136 FOR(i,1,n) if(val[i] & 1){ 137 FOR(j,1,n) 138 if((val[j] & 1) == 0 && !pm[val[i] + val[j]]) 139 MF.Add_edge(i,j,1); 140 } 141 MF.st = 0; 142 MF.ed = n + 1; 143 if(MF.Dinic() != n){ 144 printf("Impossible\n"); 145 return 0; 146 } 147 //Init 148 MEM(first,-1); 149 ecnt = 0; 150 FOR(i,1,n) if(val[i] & 1){ 151 for(int j = MF.first[i]; ~j; j = MF.next[j]){ 152 int v = MF.ver[j]; 153 if(v && MF.cp[j] == 0){ //防止连回源点 154 Add_edge(i,v); 155 Add_edge(v,i); 156 } 157 } 158 } 159 FOR(i,1,n){ 160 if(!vis[i]){ 161 res.clear(); 162 Dfs(i); 163 ans.push_back(res); 164 } 165 } 166 printf("%d\n",(int)ans.size()); 167 REP(i,ans.size()){ 168 printf("%d",(int)ans[i].size()); 169 REP(j,ans[i].size()) printf(" %d",ans[i][j]); 170 puts(""); 171 } 172 return 0; 173 }