【费用流】CurvyonRails

xiaoxiao2021-02-28  39

题意:

给出一个 (n×m) ( n × m ) 棋盘,其中有一些格子是城市,有部分城市是重要区域,要求在城市中修轨道,要求: 轨道只能放在城市之中,并且每个轨道需要与相邻的四个格子中的两个相连, 需要使每个城市都有轨道,不是城市的地方不能有轨道,城市之间不需要联通。

重要区域的轨道要尽量弯曲,即重要区域的轨道需要连接一横一纵两个方向。现在定义一种方案的代价为:重要区域直行轨道的数量。

给出这个棋盘,求出最小代价。 n,m25 n , m ≤ 25


分析:

首先,必须知道棋盘在图论算法中,是一个经典的模型:每个棋盘都是一个完美的二分图,设棋盘上某个点的坐标为 (x,y) ( x , y ) ,根据 (x+y)mod 2 ( x + y ) m o d   2 的值,将棋盘分为两部分。这就形成了一个二分图。

再回到这道题上来,题目要求:使得每个轨道需要与周围的某两个轨道相连。先忽略重要地区的问题,比较套路的做法是: 将两类点分别设为A,B,只需要 s s 向每个A中的点连一条容量为2的边,每条B的节点再向tt连一条容量为2的边。每个A类点向其周围的B类点分别连一条容量为1的边。这样如果能够满流,即可判定至少存在一种合法方案。

现在,要加入重要地区: 题目中说,若重要地区的轨道为直,就要1的代价。 这时候,就需要用到网络流建模中,最基本的技巧:拆点 我们将每个点一分为三,如下图所示: 不重要的A类城市: 重要的A类城市: 不重要的B类城市 重要的B类城市: 跑费用流即可,同样是判断是否满流,同时求出最小费用即可。

#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<string> #include<queue> #include<iostream> #define SF scanf #define PF printf #define MAXN 2010 #define MAXM 30 #define INF 0x3FFFFFFF using namespace std; int s,t,n,m; int fa[MAXN],id[MAXN],idx[MAXM][MAXM][5],d[MAXN]; int wx[5][3]={{0,1},{-1,0},{0,-1},{1,0}}; bool vis[MAXN]; vector<int> a[MAXN],w[MAXN],c[MAXN],rev[MAXN]; vector<string> mp,mpr; string mp1; bool spfa(){ memset(vis,0,sizeof vis); memset(d,0x3f3f3f3f,sizeof d); queue<int>q; vis[s]=1; fa[s]=s; d[s]=0; q.push(s); while(!q.empty()){ int fnt=q.front(); q.pop(); vis[fnt]=0; for(int i=0;i<a[fnt].size();i++){ int v=a[fnt][i]; if(w[fnt][i]&&d[v]>d[fnt]+c[fnt][i]){ d[v]=d[fnt]+c[fnt][i]; fa[v]=fnt; id[v]=i; if(vis[v]==0){ vis[v]=1; q.push(v); } } } } if(d[t]==0x3f3f3f3f) return 0; return 1; } pair<int,int> solve(){ int res=0,ans=0; while(spfa()){ int minf=INF; for(int i=t;i!=s;i=fa[i]) minf=min(minf,w[fa[i]][id[i]]); res+=minf; for(int i=t;i!=s;i=fa[i]){ w[fa[i]][id[i]]-=minf; w[i][rev[fa[i]][id[i]]]+=minf; ans+=c[fa[i]][id[i]]*minf; } } return make_pair(res,ans); } void addlink(int x,int y,int len,int cot){ a[x].push_back(y); a[y].push_back(x); w[x].push_back(len); w[y].push_back(0); c[x].push_back(cot); c[y].push_back(-cot); rev[x].push_back(a[y].size()-1); rev[y].push_back(a[x].size()-1); } void addedge(int x,int y,int flag){ if((x+y)%2==0){ addlink(s,idx[x][y][0],2,0); if(flag){ addlink(idx[x][y][0],idx[x][y][1],1,0); addlink(idx[x][y][0],idx[x][y][1],1,1); addlink(idx[x][y][0],idx[x][y][2],1,0); addlink(idx[x][y][0],idx[x][y][2],1,1); } else{ addlink(idx[x][y][0],idx[x][y][1],2,0); addlink(idx[x][y][0],idx[x][y][2],2,0); } } else{ addlink(idx[x][y][0],t,2,0); if(flag){ addlink(idx[x][y][1],idx[x][y][0],1,0); addlink(idx[x][y][1],idx[x][y][0],1,1); addlink(idx[x][y][2],idx[x][y][0],1,0); addlink(idx[x][y][2],idx[x][y][0],1,1); } else{ addlink(idx[x][y][1],idx[x][y][0],2,0); addlink(idx[x][y][2],idx[x][y][0],2,0); } } for(int i=0;i<4;i++){ int xx=x+wx[i][0]; int yy=y+wx[i][1]; if(xx<0||yy<0||xx>=n||yy>=m) continue; if(mp[xx][yy]=='w') continue; if((x+y)%2==0) addlink(idx[x][y][i%2+1],idx[xx][yy][i%2+1],1,0); } } class CurvyonRails{ public: int getmin(vector<string> &mpx){ /*SF("%d",&n); for(int i=0;i<n;i++){ cin>>mp1; mp.push_back(mp1); }*/ mp=mpx; n=mp.size(); m=mp[0].size(); for(int i=0;i<n;i++) for(int j=0;j<m;j++){ idx[i][j][0]=i*m+j; idx[i][j][1]=i*m+j+n*m; idx[i][j][2]=i*m+j+n*m*2; } s=3*n*m; t=3*n*m+1; int cnt=0,cnt1=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++){ if(mp[i][j]=='w') continue; if((i+j)%2==0) cnt++; else cnt1++; if(mp[i][j]=='C'){ addedge(i,j,1); } else{ addedge(i,j,0); } } pair<int,int> ans=solve(); if(ans.first!=cnt*2||cnt!=cnt1) return -1; else return ans.second; } }; /*int main(){ SF("%d",&n); for(int i=0;i<n;i++){ cin>>mp1; mpr.push_back(mp1); } PF("%d",sbcch.getmin(mpr)); }*/
转载请注明原文地址: https://www.6miu.com/read-2627061.html

最新回复(0)