• 【洛谷 P3965】 [TJOI2013]循环格(费用流)


    题目链接
    回路限制经典题。
    每个点拆成入点和出点,源点连每个点的出点,流量1,费用0,每个点出点连汇点,流量1,费用0,入点和出点之间没有边。
    也就是说每个点必须靠其他点流来的流量来流入汇点,同时自己的流量流出去,这时候就会形成环,只要把所有流量流满,就必定是题目要求的情形。
    所以每个点向前后左右相邻点连边,如果本来就是这个方向,费用为0,否则费用为1,最小费用即为答案。

    #include <cstdio>
    #include <queue>
    #include <cstring>
    #define INF 2147483647
    using namespace std;
    const int MAXN = 1010;
    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[20][20], mincost, l[] = {233, -1, 1, 0, 0}, r[] = {666, 0, 0, -1, 1};
    int id(int i, int j, int k){
    	return (i - 1) * m + j + k * 500;
    }
    char ch;
    int main(){
        scanf("%d%d", &n, &m); s = 999; t = 1000;
        for(int i = 1; i <= n; ++i)
    	   for(int j = 1; j <= m; ++j){
    	       ch = getchar(); while(ch == '
    ' || ch == '
    ' || ch == ' ') ch = getchar();
    	       if(ch == 'U') a[i][j] = 1;
    	       if(ch == 'D') a[i][j] = 2;
    	       if(ch == 'L') a[i][j] = 3;
    	       if(ch == 'R') a[i][j] = 4;
    	       Add(s, id(i, j, 0), 1, 0);
    	       Add(id(i, j, 1), t, 1, 0);
    	   }
    	for(int i = 1; i <= n; ++i)
    	   for(int j = 1; j <= m; ++j)
    	      for(int k = 1; k <= 4; ++k){
    	      	 int x = i + l[k], y = j + r[k];
    	      	 if(!x) x = n; if(!y) y = m; if(x > n) x = 1; if(y > m) y = 1;
    	      	 Add(id(i, j, 0), id(x, y, 1), 1, a[i][j] != k);
    	      }
        while(RoadsExist()){
          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
    ", mincost);
        return 0;
    }
    
    
  • 相关阅读:
    .net 用户控件ascx.cs注册js脚本代码无效果
    Sql-exec
    C# 复制指定节点的所有子孙节点到新建的节点下
    C# 拷贝指定文件夹下的所有文件及其文件夹到指定目录
    svn 命令
    C语言运算符优先级
    两级宏&&字符串化宏
    [C++]#if !defined 的作用
    四面体ply格式文件图和数据对应关系分析
    PLY格式介绍
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/10499554.html
Copyright © 2020-2023  润新知