• 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
    ", 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 }
    代码君
  • 相关阅读:
    android操作数据库
    Android读写SD卡上的文件
    第四章 函数与程序结构
    getchar()与EOF
    NULL, '',0 '0'的区别
    TCPL 行计数
    行计数
    getchar()用法
    在C语言中,double、long、unsigned、int、char类型数据所占字节数
    队列——解密QQ号
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4286931.html
Copyright © 2020-2023  润新知