• [BZOJ4205][FJ2015集训]卡牌配对


    题目:卡牌配对

    传送门:None

    题目大意:有$n_1$张$X$类牌和$n_2$张$Y$类类牌,每张卡牌上有三个属性值:$A,B,C$。两张卡牌能够配对,当且仅当,存在至多一项属性值使得两张卡牌该项属性值互质,且两张卡牌类别不同。每张卡牌只能用一次,最大化匹配上的卡牌组数。

    分析:

    做法一:直接上二分图匹配,然后TLE

    做法二:只有三个属性值,又存在至多一项属性值使得两张卡牌该项属性值互质

    等价于两张卡牌属性$A,B$均不互质,或属性$A,C$均不互质,或属性$B,C$均不互质

    等价于两张卡牌属性$A$有共同因子aa、属性$B$有共同因子$bb$,或属性$A$有共同因子$aa$、属性$C$有共同因子$cc$,或属性$B$有共同因子$bb$、属性$C$有共同因子$cc$,

    等价于两张卡牌属性$A$有共同质因子a、属性$B$有共同质因子$b$,或属性$A$有共同质因子$a$、属性$C$有共同质因子$c$,或属性$B$有共同质因子$b$、属性$C$有共同质因子$c$,

    这样我们在中间新建一列点$(a,b)$代表属性$A$可以被$a$整除,属性$B$可以被$b$整除,这样连向$(a,b)$的$X$类点和$Y$类点就一定会匹配

    同样的,我们建立中间节点$(a,c)$和$(b,c)$

    由于200以内有46个质数,这样会增加$46*46*3$个节点,共需要$46*46*3+n1+n2+2$个节点

    源点(节点编号:$46*46+n1+n2$)向$X$类节点(节点编号:$46*46*3+i, {i}in{[0,n_1)}$)建一条流量为1的边

    枚举中间节点,如果可以连边,$X$类节点向中间节点建一条流量为$1$的边

    枚举中间节点,如果可以连边,中间节点向$Y$类节点(节点编号:$46*46*3+n1+i,{i}in{[0,n_2)}$)建一条流量为$1$的边,

    $Y$类节点向汇点(节点编号:$46*46*3+n1+n2+1$)建一条流量为$1$的边

    由于$2*3*5*7>200$,$XY$类节点至多向中间节点连$3*3*3$条边,

    这样会有大概$(n1+n2)*3*3*3 + n1 + n2$条边.

    枚举中间节点会花费大量时间:$(n1 + n2) * 46 * 46 * 3$ ; TLE警告

    做法三:

    考虑到属性值小于200,我们可以预处理每一个$(a,b)$可以连出去的中间点编号,$(a,c)$,$(b,c)$加上$46*46$,$46*46*2$就好啦

    预处理时间:$200 * 200 * 46 * 46$

    考虑到大量属性值点对可能不会出现,于是采用类似记忆化的做法加速

    每个属性点可以先预处理出他的质因数,这样可以再优化一下

    这道题节点数和边数非常的多,然后“请大胆使用渐进复杂度较高的做法”是通过本题的关键 = =

    代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int MAXN = 80005;
      4 const int MAXM = 4000005;
      5 const int INF = 1e9 + 7;
      6 typedef int LL;
      7 int pn;
      8 vector <int> prime, markp[201], mark[201][201];
      9 void init() {
     10     for(int i = 2; i <= 200; i++) {
     11         int fg = 1;
     12         for(int j = 2; j < i; j++)
     13             if(i % j == 0) fg = 0;
     14         if(fg) prime.push_back(i);
     15     }
     16     pn = prime.size();
     17     for(int i = 2; i <= 200; i++)
     18     for(int j = 0; j < (int)prime.size(); j++)
     19         if(i % prime[j] == 0) markp[i].push_back(j);
     20 }
     21 void getMark(int a, int b) {
     22     for(auto i : markp[a])
     23     for(auto j : markp[b]) 
     24         if(a % prime[i] == 0 && b % prime[j] == 0) 
     25             mark[a][b].push_back(i * pn + j);
     26 }
     27 namespace NWF {
     28     struct Edge {
     29         int to, nxt;LL f;
     30     } e[MAXM << 1]; 
     31     int S, T, tot;
     32     int ecnt, head[MAXN], cur[MAXN], dis[MAXN];
     33     queue<int> q;
     34     void init(int _S, int _T, int _tot){
     35         ecnt = 1; S = _S; T = _T; tot = _tot;
     36         memset(head, 0, (tot + 1) * sizeof(int));
     37     } 
     38     void addEdge(int u, int v, LL f) {
     39         e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
     40         e[++ecnt] = (Edge) {u, head[v], 0}; head[v] = ecnt;
     41     }
     42     bool bfs() {
     43         memset(dis, 0, (tot + 1) * sizeof(int));
     44         q.push(S); dis[S] = 1;
     45         while (!q.empty()) {
     46             int u = q.front(), v; q.pop();
     47             for (int i = cur[u] = head[u]; i ; i = e[i].nxt) {
     48                 if (e[i].f && !dis[v = e[i].to]) {
     49                     q.push(v);
     50                     dis[v] = dis[u] + 1;
     51                 }
     52             }
     53         }
     54         return dis[T];
     55     }
     56     LL dfs(int u, LL maxf) {
     57         if (u == T) return maxf;
     58         LL sumf = maxf;
     59         for (int &i = cur[u]; i; i = e[i].nxt) {
     60             if (e[i].f && dis[e[i].to] > dis[u]) {
     61                 LL tmpf = dfs(e[i].to, min(sumf, e[i].f));
     62                 e[i].f -= tmpf; e[i ^ 1].f += tmpf;
     63                 sumf -= tmpf;
     64                 if (!sumf) return maxf;
     65             }
     66         }
     67         return maxf - sumf;
     68     }
     69     LL dinic() {
     70         LL ret = 0;
     71         while (bfs()) ret += dfs(S, INF);
     72         return ret;
     73     }
     74 }
     75 int main() {
     76     freopen("4205_19.in","r",stdin);
     77     init();
     78     int n1, n2;
     79     scanf("%d%d",&n1,&n2);
     80     int n = n1 + n2;
     81     NWF::init(pn *pn * 3 + n, pn * pn * 3 + n + 1, pn * pn * 3 + n + 2);
     82     for(int k = 0,a,b,c; k < n1; k++) {
     83         scanf("%d%d%d",&a,&b,&c);
     84         int id = pn * pn * 3 + k;
     85         NWF::addEdge(NWF::S, id, 1);
     86         if(mark[a][b].size() == 0 && a != 1 && b != 1) getMark(a, b);
     87         if(mark[a][c].size() == 0 && a != 1 && c != 1) getMark(a, c);
     88         if(mark[b][c].size() == 0 && b != 1 && c != 1) getMark(b, c);
     89         for(auto it : mark[a][b]) NWF::addEdge(id, it, 1);
     90         for(auto it : mark[a][c]) NWF::addEdge(id, pn*pn+it, 1);
     91         for(auto it : mark[b][c]) NWF::addEdge(id, 2*pn*pn+it, 1);
     92     }
     93     for(int k = 0,a,b,c; k < n2; k++) {
     94         scanf("%d%d%d",&a,&b,&c);
     95         int id = pn * pn * 3 + n1 + k;
     96         NWF::addEdge(id, NWF::T, 1);
     97         if(mark[a][b].size() == 0 && a != 1 && b != 1) getMark(a, b);
     98         if(mark[a][c].size() == 0 && a != 1 && c != 1) getMark(a, c);
     99         if(mark[b][c].size() == 0 && b != 1 && c != 1) getMark(b, c);
    100         for(auto it : mark[a][b]) NWF::addEdge(it, id, 1);
    101         for(auto it : mark[a][c]) NWF::addEdge(pn*pn+it, id, 1);
    102         for(auto it : mark[b][c]) NWF::addEdge(2*pn*pn+it, id, 1);
    103     }
    104     int ans = NWF::dinic();
    105     printf("%d
    ",ans);
    106     return 0;
    107 }
    dinic
      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int MAXN = 80005;
      4 const int MAXM = 4000005;
      5 const int INF = 1e9 + 7;
      6 typedef int LL;
      7 int pn;
      8 vector <int> prime, markp[201], mark[201][201];
      9 void init() {
     10     for(int i = 2; i <= 200; i++) {
     11         int fg = 1;
     12         for(int j = 2; j < i; j++)
     13             if(i % j == 0) fg = 0;
     14         if(fg) prime.push_back(i);
     15     }
     16     pn = prime.size();
     17     for(int i = 2; i <= 200; i++)
     18     for(int j = 0; j < (int)prime.size(); j++)
     19         if(i % prime[j] == 0) markp[i].push_back(j);
     20 }
     21 void getMark(int a, int b) {
     22     for(auto i : markp[a])
     23     for(auto j : markp[b]) 
     24         if(a % prime[i] == 0 && b % prime[j] == 0) 
     25             mark[a][b].push_back(i * pn + j);
     26 }
     27 namespace NWF {
     28     struct Edge{
     29         int to, nxt;LL f;
     30     }e[MAXM << 1];
     31     int S, T, tot;
     32     int ecnt, head[MAXN], cur[MAXN], pre[MAXN], num[MAXN], dis[MAXN];
     33     queue<int> q;
     34     void init(int _S, int _T, int _tot){
     35         ecnt = 1; S = _S; T = _T; tot = _tot;
     36         memset(num,  0, (tot + 1) * sizeof(int));
     37         memset(head, 0, (tot + 1) * sizeof(int));
     38     } 
     39     inline void addEdge(int u, int v, LL f) {
     40         e[++ecnt] = (Edge) {v, head[u], f}; head[u] = ecnt;
     41         e[++ecnt] = (Edge) {u, head[v], 0}; head[v] = ecnt;
     42     }
     43     void bfs() {
     44         memset(dis, 0, (tot + 1) * sizeof(int));
     45         q.push(T);
     46         dis[T] = 1;
     47         while(!q.empty()) {
     48             int u = q.front(), v; q.pop();
     49             num[dis[u]]++;
     50             for(int i = cur[u] = head[u]; i; i = e[i].nxt) {
     51                 if(!dis[v = e[i].to]) {
     52                     dis[v] = dis[u] + 1;
     53                     q.push(v);
     54                 }
     55             }
     56         }
     57     }
     58     LL augment() {
     59         LL flow = INF;
     60         for(int i = S; i != T; i = e[cur[i]].to) 
     61             flow = min(flow, e[cur[i]].f);
     62         for(int i = S; i != T; i = e[cur[i]].to) {
     63             e[cur[i]].f -= flow;
     64             e[cur[i] ^ 1].f += flow;
     65         }
     66         return flow;
     67     }
     68     LL isap() {
     69         bfs();
     70         int u = S, v;
     71         LL flow = 0;
     72         while(dis[S] <= tot) {
     73             if(u == T) {
     74                 flow += augment();
     75                 u = S;
     76             }
     77             bool fg = 0;
     78             for(int i = cur[u]; i; i = e[i].nxt) {
     79                 if(e[i].f && dis[u] > dis[v = e[i].to]) {
     80                     pre[v] = u;
     81                     cur[u] = i;
     82                     u = v;
     83                     fg = 1;
     84                     break;
     85                 }
     86             }
     87             if(fg) continue;
     88             if(!--num[dis[u]]) break;
     89             int maxDis = tot;
     90             for(int i = head[u]; i; i = e[i].nxt) {
     91                 if(e[i].f && maxDis > dis[v = e[i].to]) {
     92                     maxDis = dis[v];
     93                     cur[u] = i;
     94                 }
     95             }
     96             num[dis[u] = maxDis + 1]++;
     97             if(u != S) u = pre[u];
     98         }
     99         return flow;
    100     }
    101 }
    102 int main() {
    103     init();
    104     int n1, n2;
    105     scanf("%d%d",&n1,&n2);
    106     int n = n1 + n2;
    107     NWF::init(pn *pn * 3 + n, pn * pn * 3 + n + 1, pn * pn * 3 + n + 2);
    108     for(int k = 0,a,b,c; k < n1; k++) {
    109         scanf("%d%d%d",&a,&b,&c);
    110         int id = pn * pn * 3 + k;
    111         NWF::addEdge(NWF::S, id, 1);
    112         if(mark[a][b].size() == 0 && a != 1 && b != 1) getMark(a, b);
    113         if(mark[a][c].size() == 0 && a != 1 && c != 1) getMark(a, c);
    114         if(mark[b][c].size() == 0 && b != 1 && c != 1) getMark(b, c);
    115         for(auto it : mark[a][b]) NWF::addEdge(id, it, 1);
    116         for(auto it : mark[a][c]) NWF::addEdge(id, pn*pn+it, 1);
    117         for(auto it : mark[b][c]) NWF::addEdge(id, 2*pn*pn+it, 1);
    118     }
    119     for(int k = 0,a,b,c; k < n2; k++) {
    120         scanf("%d%d%d",&a,&b,&c);
    121         int id = pn * pn * 3 + n1 + k;
    122         NWF::addEdge(id, NWF::T, 1);
    123         if(mark[a][b].size() == 0 && a != 1 && b != 1) getMark(a, b);
    124         if(mark[a][c].size() == 0 && a != 1 && c != 1) getMark(a, c);
    125         if(mark[b][c].size() == 0 && b != 1 && c != 1) getMark(b, c);
    126         for(auto it : mark[a][b]) NWF::addEdge(it, id, 1);
    127         for(auto it : mark[a][c]) NWF::addEdge(pn*pn+it, id, 1);
    128         for(auto it : mark[b][c]) NWF::addEdge(2*pn*pn+it, id, 1);
    129     }
    130     int ans = NWF::isap();
    131     printf("%d
    ",ans);
    132     return 0;
    133 }
  • 相关阅读:
    DOM节点类型
    javascript中的变量、作用域
    this 不同情况指代的对象
    BOM对象节点
    浏览器兼容性
    总结
    javascript事件流讲解和实例应用
    7.20
    7.16总结
    飞机大战
  • 原文地址:https://www.cnblogs.com/hjj1871984569/p/11830917.html
Copyright © 2020-2023  润新知