zoukankan      html  css  js  c++  java
  • 【洛谷 P4134】 [BJOI2012]连连看(费用流)

    题目链接
    首先是可以(O(n^2))枚举出所有符合要求的点对的,然后考虑建图。
    还是拆点把每个点拆成入点和出点,源点连入点,出点连汇点,流量都是1,费用都是0。
    然后对于没对符合要求的((x,y)),连接((x_{in},y_{out}),(y_{in},x_{out})),费用均为(x+y),流量均为(1)
    然后跑出最大费用最大流,最大流除以2就是第一问,最大费用除以2就是第二问。

    为什么要双向连边然后答案除以2?单向连边去试试就知道了
    PS:会重复。

    #include <cstdio>
    #include <queue>
    #include <cmath>
    #include <cstring>
    #define INF 2147483647
    using namespace std;
    const int MAXN = 5010;
    const int MAXM = 200010;
    queue <int> q; 
    int s, t, now, n, m;
    struct Edge{
        int from, next, to, rest, cost;
    }e[MAXM];
    int head[MAXN], num = 1, dis[MAXN], vis[MAXN], Flow[MAXN], pre[MAXN];
    inline void Add(int from, int to, int flow, int cost){
        e[++num] = (Edge){ from, head[from], to, flow, cost }; head[from] = num;
        e[++num] = (Edge){ to, head[to], from, 0, -cost }; head[to] = num;
    }
    int RoadsExist(){
        q.push(s);
        memset(dis, 127, sizeof dis);
        dis[s] = 0; Flow[s] = INF; pre[t] = 0;
        while(!q.empty()){
          now = q.front(); q.pop(); vis[now] = 0;
          for(int i = head[now]; i; i = e[i].next)
             if(e[i].rest && dis[e[i].to] > dis[now] + e[i].cost){
               dis[e[i].to] = dis[now] + e[i].cost;
               pre[e[i].to] = i;
               Flow[e[i].to] = min(Flow[now], e[i].rest);
               if(!vis[e[i].to]){
                 vis[e[i].to] = 1;
                 q.push(e[i].to);
               }
             }
        }
        return pre[t];
    }
    int a, b, c, d, maxflow, mincost;
    int gcd(int a, int b){
    	return b ? gcd(b, a % b) : a;
    }
    int main(){
        scanf("%d%d", &a, &b); s = 4999; t = 5000;
        for(int i = a; i <= b; ++i){
           Add(s, i, 1, 0);
           Add(i + 1000, t, 1, 0);
           for(int j = a; j < i; ++j){
              c = i * i - j * j;
              d = sqrt(c);
              if(d * d == c && gcd(d, j) == 1){
              	Add(i, j + 1000, 1, -i - j);
              	Add(j, i + 1000, 1, -i - j);
              }
           }
        }
        while(RoadsExist()){
          maxflow += Flow[t];
          mincost += Flow[t] * dis[t];
          for(int i = t; i != s; i = e[pre[i]].from){
             e[pre[i]].rest -= Flow[t];
             e[pre[i] ^ 1].rest += Flow[t];
          }
        }
        printf("%d %d
    ", maxflow >> 1, -mincost >> 1);
        return 0;
    }
    
    
  • 相关阅读:
    结对编程项目作业4
    团队编程项目进度
    团队编程项目作业2-团队编程项目代码设计规范
    现代软件工程 阅读笔记
    个人编程作业1-GIT应用
    结对编程项目作业2-开发环境搭建过程
    结对编程项目作业2-结对编项目设计文档
    课后作业-阅读任务-阅读提问
    《团队-科学计算器-模块测试过程》
    团队-科学计算器-模块开发过程
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/10500109.html
Copyright © 2011-2022 走看看