日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ-3171-循环格-TJOI2013-费用流

發布時間:2025/3/15 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ-3171-循环格-TJOI2013-费用流 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

描述

一個循環格就是一個矩陣,其中所有元素為箭頭,指向相鄰四個格子。每個元素有一個坐標(行,列),其中左上角元素坐標為(0,0)。給定一個起始位置(r,c)

,你可以沿著箭頭防線在格子間行走。即如果(r,c)是一個左箭頭,那么走到(r,c-1);如果是右箭頭那么走到(r,c+1);如果是上箭頭那么走到(r-1,c);如果是下箭頭那么走到(r+1,c);每一行和每一列都是循環的,即如果走出邊界,你會出現在另一側。

一個完美的循環格是這樣定義的:對于任意一個起始位置,你都可以i沿著箭頭最終回到起始位置。如果一個循環格不滿足完美,你可以隨意修改任意一個元素的箭頭直到完美。給定一個循環格,你需要計算最少需要修改多少個元素使其完美。


分析

  • 和星際競速那道題有相通之處. 當時做星際競速時總結的建模方法在這里用到了.
  • 凡是遇到使每個點都經過一次的題目就可以考慮拆點建圖. 拆點, S向Xi連一條容量為1費用為0的邊, 表示從X出發. Yi向T連一條容量為1費用為0的邊, 表示到達Y.
  • 格子X的Xi向原方向指向的格子Y的Yj連一條容量為INF, 費用為0的邊, 向另外三個方向指向的格子連一條容量為INF, 費用為1的邊. 表示修改.

代碼
#include #include #include #include #include using namespace std; const int INF = 1000000000; const int maxn = 2*15*15 + 10; struct Edge { int from, to, cap, flow, cost; }; struct MCMF { int n, m, s, t; vectoredges; vectorG[maxn]; int inq[maxn], d[maxn], p[maxn], a[maxn]; void init(int n, int s, int t) { this->n = n; this->s = s; this->t = t; } void AddEdge(int from, int to, int cap, int cost) { edges.push_back((Edge){from, to, cap, 0, cost}); edges.push_back((Edge){to, from, 0, 0, -cost}); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int& cost) { for(int i = 0; i < n; i++) d[i] = INF; memset(inq, 0, sizeof(inq)); d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; queueQ; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for(int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if(e.cap > e.flow && d[e.to] > d[u] + e.cost) { d[e.to] = d[u] + e.cost; p[e.to] = G[u][i]; a[e.to] = min(a[u], e.cap - e.flow); if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; } } } } if(d[t] == INF) return false; cost += d[t] * a[t]; int u = t; while(u != s) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; u = edges[p[u]].from; } return true; } int Mincost() { int cost = 0; while(BellmanFord(cost)); return cost; } }g; int id[maxn][maxn]; int main() { int n, m, s, t; scanf("%d %d", &n, &m); int c = 0; for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) id[i][j] = ++c; g.init(c+c+2, s=0, t=c+c+1); for(int i = 0; i < n; i++) { char str[20]; scanf("%s", str); for(int j = 0; j < m; j++) { g.AddEdge(s, id[i][j], 1, 0); g.AddEdge(id[i][j]+c, t, 1, 0); switch(str[j]) { case 'U': g.AddEdge(id[i][j], id[(i+n-1)%n][j]+c, INF, 0); g.AddEdge(id[i][j], id[(i+1)%n][j]+c, INF, 1); g.AddEdge(id[i][j], id[i][(j+m-1)%m]+c, INF, 1); g.AddEdge(id[i][j], id[i][(j+1)%m]+c, INF, 1); break; case 'D': g.AddEdge(id[i][j], id[(i+n-1)%n][j]+c, INF, 1); g.AddEdge(id[i][j], id[(i+1)%n][j]+c, INF, 0); g.AddEdge(id[i][j], id[i][(j+m-1)%m]+c, INF, 1); g.AddEdge(id[i][j], id[i][(j+1)%m]+c, INF, 1); break; case 'L': g.AddEdge(id[i][j], id[(i+n-1)%n][j]+c, INF, 1); g.AddEdge(id[i][j], id[(i+1)%n][j]+c, INF, 1); g.AddEdge(id[i][j], id[i][(j+m-1)%m]+c, INF, 0); g.AddEdge(id[i][j], id[i][(j+1)%m]+c, INF, 1); break; case 'R': g.AddEdge(id[i][j], id[(i+n-1)%n][j]+c, INF, 1); g.AddEdge(id[i][j], id[(i+1)%n][j]+c, INF, 1); g.AddEdge(id[i][j], id[i][(j+m-1)%m]+c, INF, 1); g.AddEdge(id[i][j], id[i][(j+1)%m]+c, INF, 0); break; } } } printf("%d\n", g.Mincost()); return 0; }

總結

以上是生活随笔為你收集整理的BZOJ-3171-循环格-TJOI2013-费用流的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。