传送门
题解:
先不考虑那个最小化,如何判断有没有解?
将整张图黑白染色,只考虑非障碍格子,源点向每个黑格连容量为2的边,每个白格向汇点连容量为2的边,然后黑格向所有相邻的白格连容量为1的边,很显然有解当且仅当满流。
然后我们对于每个格子拆两个点,表示从横向还是纵向来的,格子之间的连边按照方向来,为了表示出代价,源汇连出来的边全部拆成两个,向两个点分别连容量为1的边,然后两点之间连容量为1,代价为1的边。
跑最小费用最大流。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::string;
class CurvyonRails{
private:
static cs int N=2e4+7,M=35;
int S,T,tot,n,m,id1[M][M],id2[M][M];
struct edge{int to,cap,w,rev;};
typedef std::vector<edge>::iterator iter;
std::vector<edge> G[N];iter cur[N];
inline void adde(int u,int v,int cap,int cost){
G[u].push_back((edge){v,cap,cost,G[v].size()});
G[v].push_back((edge){u,0,-cost,G[u].size()-1});
}
int dis[N],vis[N];
inline bool SPFA(){
memset(dis+1,0x3f,sizeof(int)*tot);
std::queue<int> q;q.push(S);dis[S]=0;
while(!q.empty()){
int u=q.front();q.pop();vis[u]=false;cur[u]=G[u].begin();
for(auto e:G[u])if(e.cap&&dis[e.to]>dis[u]+e.w){
dis[e.to]=dis[u]+e.w;
if(!vis[e.to])vis[e.to]=true,q.push(e.to);
}
}
return dis[T]<1e9;
}
int tot_flow,tot_cost;
inline int dfs(int u,int flow){
if(u==T){
tot_flow+=flow;
tot_cost+=flow*dis[T];
return flow;
}
int ans=0;vis[u]=true;
for(iter &e=cur[u];e!=G[u].end();++e)
if(e->cap&&dis[e->to]==dis[u]+e->w&&!vis[e->to]){
int delta=dfs(e->to,std::min(flow-ans,e->cap));
if(delta){
e->cap-=delta;
G[e->to][e->rev].cap+=delta;
if((ans+=delta)==flow)break;
}
}
vis[u]=false;return ans;
}
inline void Flow(){
tot_flow=tot_cost=0;
while(SPFA())dfs(S,0x3f3f3f3f);
}
public:
CurvyonRails(){}
int getmin(std::vector<string> s){
n=s.size(),m=s[0].size();
S=1,T=tot=2;int ct=0,cnt=0;
for(int re i=0;i<n;++i)
for(int re j=0;j<m;++j)
if(s[i][j]!='w')id1[i][j]=++tot,id2[i][j]=++tot;
for(int re i=0;i<n;++i)
for(int re j=0;j<m;++j)if(id1[i][j]){
if((i^j)&1){
++ct;++cnt;
adde(id1[i][j],T,1,0);
adde(id2[i][j],T,1,0);
}
else {
--ct;++cnt;
adde(S,id1[i][j],1,0);
adde(S,id2[i][j],1,0);
for(int re k=0;k<4;++k){
static cs int dx[]={0,1,0,-1};
static cs int dy[]={1,0,-1,0};
int x=i+dx[k],y=j+dy[k];
if(!~x||x==n||!~y||y==m||s[x][y]=='w')continue;
if(k&1)adde(id1[i][j],id2[x][y],1,0);
else adde(id2[i][j],id1[x][y],1,0);
}
}
int cost=s[i][j]=='C'?1:0;
adde(id1[i][j],id2[i][j],1,cost);
adde(id2[i][j],id1[i][j],1,cost);
}
if(ct)return -1;Flow();
if(tot_flow!=cnt)return -1;
return tot_cost;
}
};
#ifdef zxyoi
CurvyonRails Solver;
signed main(){
std::cout<<Solver.getmin(
{"CC..CCCw.CwC..CC.w.C",
"C.CCCwCCC.w.w..C.w..",
"wwww...CC.wC.Cw.CC..",
"CC..CC.w..w.C..CCCC.",
"CC.CCC..CwwCCC.wCC..",
"w.C..wwCC.CC.wwwCC..",
".CC.CC..CCC..CC.CC.C",
"Cw....C.C.CCC...CC..",
"CC.C..Cww.C.CwwwC..w",
"wCCww..C...CCCCCCC.w",
"C.CCw.CC.ww...C.CCww",
"C.C.C.CCwCC..wCCw.Cw",
"CCC.C...w..C.wC.wCCw",
"CC.C..C..CCC.CC.C...",
"C.ww...CCC..CC...CCC",
"...CCC.CwwwC..www.C.",
"wwCCCCC.w.C.C...wCwC",
"CCwC.CwCCC.C.w.Cw...",
"C.w.wC.CC.CCC.C.w.Cw",
"CCw.CCC..C..CC.CwCCw",
"C.wwwww.CwwCCwwwwwww"}
)<<"\n";
return 0;
}
#endif