codeforces #284 div2 E(最大流)

2014-12-25 13:00:32

思路:好题。

  由于题目保证ik+jk为奇数,所以必然是一奇一偶,考虑a[ik],a[jk]相约,可知要先素数分解然后逐个消掉。

  因为要求最大相约次数,考虑三种策略:贪心,DP,网络流。

  一开始想贪心...画画图就否定掉了,DP?貌似也没啥思路。

  正解是网络流,建立总源点,与每个偶数位置的数的素数因子相连,边的容量是因子的个数。建立总汇点,每个奇数位置的数的素数因子与之相连,容量为因子数。

  然后根据m条i、j在偶数位置数和奇数位置数之间建边,流量为无穷。

  然后跑一遍最大流即可。(PS:这种求最优解的问题要注意考虑到有网络流这一解法!)

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <set>
  7 #include <map>
  8 #include <queue>
  9 #include <stack>
 10 #include <algorithm>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef unsigned long long ull;
 14 typedef pair<int,int> pii;
 15 #define MP(a,b) make_pair(a,b)
 16 const int maxv = 1000;
 17 const int maxe = 1000;
 18 const int INF = 1 << 30;
 19 
 20 int n,m;
 21 int sz[maxv];
 22 vector<pii> fac[maxv];
 23 
 24 struct Max_flow{
 25     int first[maxv],nxt[maxe],ver[maxe],cp[maxe],ecnt;
 26     int lev[maxv],st,ed;
 27     void Init(){
 28         memset(first,-1,sizeof(first));
 29         ecnt = 0;
 30     }
 31     void Add_edge(int u,int v,int c){
 32         nxt[ecnt] = first[u];
 33         ver[ecnt] = v,cp[ecnt] = c;
 34         first[u] = ecnt++;
 35         //opposite
 36         nxt[ecnt] = first[v];
 37         ver[ecnt] = u,cp[ecnt] = 0;
 38         first[v] = ecnt++;
 39     }
 40     bool Bfs(){
 41         queue<int> Q;
 42         memset(lev,-1,sizeof(lev));
 43         Q.push(st);
 44         lev[st] = 0;
 45         while(!Q.empty()){
 46             int now = Q.front(); Q.pop();
 47             for(int i = first[now]; ~i; i = nxt[i]){
 48                 int v = ver[i];
 49                 if(lev[v] < 0 && cp[i] > 0){
 50                     lev[v] = lev[now] + 1;
 51                     Q.push(v);
 52                 }
 53             }
 54         }
 55         return lev[ed] != -1;
 56     }
 57     int Dfs(int p,int minf){
 58         if(p == ed) return minf;
 59         for(int i = first[p]; ~i; i = nxt[i]){
 60             int v = ver[i];
 61             if(lev[v] > lev[p] && cp[i] > 0){
 62                 int d = Dfs(v,min(cp[i],minf));
 63                 if(d > 0){
 64                     cp[i] -= d;
 65                     cp[i ^ 1] += d;
 66                     return d;
 67                 }
 68             }
 69         }
 70         return 0;
 71     }
 72     int Dinic(){
 73         int max_flow = 0,plus;
 74         while(Bfs()){
 75             while((plus = Dfs(st,INF)) > 0)
 76                 max_flow += plus;
 77         }
 78         return max_flow;
 79     }
 80 };
 81 
 82 
 83 int main(){
 84     int l,r,t1;
 85     Max_flow MF;
 86     MF.Init();
 87     scanf("%d%d",&n,&m);
 88     for(int i = 1; i <= n; ++i){
 89         scanf("%d",&t1);
 90         for(int j = 2; j * j <= t1; ++j) if(t1 % j == 0){
 91             int cnt = 0;
 92             while(t1 % j == 0) t1 /= j,cnt++;
 93             fac[i].push_back(MP(j,cnt));
 94         }
 95         if(t1 > 1) fac[i].push_back(MP(t1,1));
 96         sz[i] = sz[i - 1] + fac[i].size();
 97     }
 98     MF.st = sz[n] + 1;
 99     MF.ed = sz[n] + 2;
100     for(int i = 1; i <= n; ++i){
101         for(int j = 0; j < fac[i].size(); ++j){
102             //if : even position , else : odd position
103             if(i % 2 == 0)    MF.Add_edge(MF.st,sz[i - 1] + j,fac[i][j].second);
104             else MF.Add_edge(sz[i - 1] + j,MF.ed,fac[i][j].second);
105         }
106     }
107     for(int k = 1; k <= m; ++k){
108         scanf("%d%d",&l,&r);
109         if(l % 2) swap(l,r); //two positions , the left is even and the right is odd
110         for(int i = 0; i < fac[l].size(); ++i){
111             for(int j = 0; j < fac[r].size(); ++j){
112                 if(fac[l][i].first == fac[r][j].first)
113                     MF.Add_edge(sz[l - 1] + i,sz[r - 1] + j,INF);
114             }
115         }
116     }
117     printf("%d\n",MF.Dinic());
118     return 0;
119 }

 

posted @ 2014-12-25 13:16  Naturain  阅读(134)  评论(0编辑  收藏  举报