【洛谷 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;
}

原文地址:https://www.cnblogs.com/Qihoo360/p/10499554.html