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 }
代码君

 

你可能感兴趣的:(codeforces)