CodeForces Round #290 Fox And Dinner

而是Div2的最后一题,当时打比赛的时候还不会最大流。自己能够把它写出来然后1A还是很开心的。

题意:

有n个不小于2的整数,现在要把他们分成若干个圈。在每个圈中,数字的个数不少于3个,而且相邻的两个数之和是质数。

分析:

因为每个数都不小于2,所以相加得到的质数一定是奇数,那么在某个圈中,一定是奇偶相间的。

也就是 奇数相邻的两个数是偶数,偶数相邻的两个数是奇数。

所以一个圈中的数字一定是偶数个,所有的输入中也必须是偶数和奇数的个数相同才可能有解。

这转化为了二分图匹配,其中X是奇数,Y是偶数,如果X和Y中的两个数加起来是质数,则连一条容量为1的边。

因为每个奇数的两边是偶数,所以将X中的点与源点连一条容量为2的边。

同样地,将Y中的点与汇点连一条容量为2的边。

求一次最大流,如果满载也就是流量为n的话,说明有解。

 

输出解:可以根据求解最大流的时候,找到的路径,再建一个图,然后DFS找环。

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int maxn = 200 + 10;
  6 const int INF = 1000000000;
  7 
  8 struct Edge
  9 {
 10     int from, to, cap, flow;
 11     Edge(int u, int v, int c, int f): from(u), to(v), cap(c), flow(f) {}
 12 };
 13 
 14 struct EdmondsKarp
 15 {
 16     int n, m;
 17     vector<Edge> edges;
 18     vector<int> G[maxn];
 19     int a[maxn];    //可改进量
 20     int p[maxn];    //上一条弧
 21 
 22     void Init(int n)
 23     {
 24         for(int i = 0; i < n; ++i) G[i].clear();
 25         edges.clear();
 26     }
 27 
 28     void AddEdge(int from, int to, int cap)
 29     {
 30         edges.push_back(Edge(from, to, cap, 0));
 31         edges.push_back(Edge(to, from, 0, 0));
 32         m = edges.size();
 33         G[from].push_back(m-2);
 34         G[to].push_back(m-1);
 35     }
 36 
 37     int MaxFlow(int s, int t)
 38     {
 39         int flow = 0;
 40         for(;;)
 41         {
 42             memset(a, 0, sizeof(a));
 43             queue<int> Q;
 44             Q.push(s);
 45             a[s] = INF;
 46             while(!Q.empty())
 47             {
 48                 int x = Q.front(); Q.pop();
 49                 for(int i = 0; i < G[x].size(); ++i)
 50                 {
 51                     Edge& e = edges[G[x][i]];
 52                     if(!a[e.to] && e.cap > e.flow)
 53                     {
 54                         a[e.to] = min(a[x], e.cap - e.flow);
 55                         p[e.to] = G[x][i];
 56                         Q.push(e.to);
 57                     }
 58                 }
 59                 if(a[t]) break;
 60             }
 61             if(!a[t]) break;
 62             for(int u = t; u != s; u = edges[p[u]].from)
 63             {
 64                 edges[p[u]].flow +=  a[t];
 65                 edges[p[u]^1].flow -= a[t];
 66             }
 67             flow += a[t];
 68         }
 69         return flow;
 70     }
 71 }g;
 72 
 73 int a[maxn], odd[maxn], even[maxn], p1, p2;
 74 vector<int> G[maxn], ans[maxn];
 75 const int maxp = 20000;
 76 bool prime[maxp + 10], vis[maxn];
 77 
 78 void prime_table()
 79 {
 80     int m = sqrt(maxp + 0.5);
 81     for(int i = 2; i <= m; ++i) if(!prime[i])
 82         for(int j = i*i; j <= maxp; j += i) prime[j] = true;
 83 }
 84 
 85 void find_circle(int cnt, int u)
 86 {
 87     ans[cnt].push_back(u);
 88     vis[u] = true;
 89     for(int i = 0; i < G[u].size(); ++i)
 90     {
 91         int v = G[u][i];
 92         if(!vis[v]) find_circle(cnt, v);
 93     }
 94 }
 95 
 96 int main()
 97 {
 98     //freopen("in.txt", "r", stdin);
 99 
100     int n;
101     scanf("%d", &n);
102     g.Init(n+2);
103     for(int i = 1; i <= n; ++i)
104     {
105         scanf("%d", &a[i]);
106         if(a[i] & 1) odd[p1++] = i;
107         else even[p2++] = i;
108     }
109     if(p1 != p2) { puts("Impossible"); return 0; }//奇数和偶数个数不同
110 
111     for(int i = 0; i < p1; ++i)
112     {
113         g.AddEdge(0, odd[i], 2);
114         g.AddEdge(even[i], n+1, 2);
115     }
116 
117     prime_table();
118     for(int i = 0; i < p1; ++i)
119         for(int j = 0; j < p1; ++j)
120             if(!prime[ a[odd[i]] + a[even[j]] ])
121                 g.AddEdge(odd[i], even[j], 1);
122 
123     int flow = g.MaxFlow(0, n+1);
124     if(flow != n) { puts("Impossible"); return 0; }
125 
126     for(int i = 0; i < g.edges.size(); ++i)
127     {//为了寻找路径,建一个新图
128         Edge& e = g.edges[i];
129         if(e.cap == 1 && e.flow == 1)
130         {
131             G[e.from].push_back(e.to);
132             G[e.to].push_back(e.from);
133         }
134     }
135 
136     int cnt = 0;
137     for(int i = 1; i <= n; ++i) if(!vis[i]) find_circle(cnt++, i);
138 
139     printf("%d\n", cnt);
140     for(int i = 0; i < cnt; ++i)
141     {
142         printf("%d %d", ans[i].size(), ans[i][0]);
143         for(int j = 1; j < ans[i].size(); ++j) printf(" %d", ans[i][j]);
144         puts("");
145     }
146 
147     return 0;
148 }
代码君

 

posted @ 2015-02-11 20:39  AOQNRMGYXLMV  阅读(208)  评论(0编辑  收藏  举报