1 条题解
-
0
简单费用流,5min 秒了。
观察
考虑循环格的性质,不难发现我们可以把每个格子看做一个节点,那么每个节点便都有一个出度指向其他节点。这个就很像内向基环树的性质啊,如果循环格合法(从每个点出发能回到自己),那么就得满足每个点都在一个环中。问题就转化为我们要最小化操作次数,使得所有点都在一个环里。
继续考虑环的性质,显然形成环是需要每个点入度都是 ,出度也都是 。出度的限制已经满足了,我们只要让每个点的入度都是 即可。这应该是一个很典的 trick 了吧。
建模
到这里就是好做的了。你发现把每个点拆成入点和出点,把每个节点能旋转到的四个方向分别看做容量为 的边,不用旋转的方向费用为 ,其余三个方向费用为 ,跑最小费用最大流即可。本质上就是个二分图匹配。
时间复杂度为 EK 或者 Dinic 的复杂度。
代码
#include <bits/stdc++.h> #define fi first #define se second #define eb(x) emplace_back(x) #define pb(x) push_back(x) #define lc(x) (tr[x].ls) #define rc(x) (tr[x].rs) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef long double ldb; using pi=pair<int,int>; const int N=1005,M=1000005; const ll inf=0x3f3f3f3f3f3f3f3f; int n,m,s,t; void getpos(int &x,int &y,int twd) { if(twd==0)x+=1; else if(twd==1)x-=1; else if(twd==2)y+=1; else if(twd==3)y-=1; if(x==0)x=n; else if(x==n+1)x=1; if(y==0)y=m; else if(y==m+1)y=1; } int getid(int x,int y,int tp) { return ((x-1)*m+y+tp*n*m); } int h[N],cur[N],idx=1; struct Edge{ int v,ne; ll c,w; }e[M]; void add(int u,int v,ll c,ll w) { e[++idx]={v,h[u],c,w}; h[u]=idx; } void addeg(int u,int v,ll c,ll w) { add(u,v,c,w); add(v,u,0,-w); } ll dis[N],cost; bitset<N>vis; bool SPFA() { memset(dis,0x3f,sizeof(dis)); vis.reset(); queue<int>q; dis[s]=0; q.push(s); vis[s]=1; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=h[u];i;i=e[i].ne) { int v=e[i].v;ll c=e[i].c,w=e[i].w; if(dis[v]>dis[u]+w&&c) { dis[v]=dis[u]+w; if(vis[v]==0) { vis[v]=1; q.push(v); } } } } return (dis[t]<=inf/2); } ll dfs(int u,ll mf) { if(u==t)return mf; ll sm=0; vis[u]=1; for(int i=cur[u];i;i=e[i].ne) { int v=e[i].v;ll c=e[i].c,w=e[i].w; if(vis[v]==0&&dis[v]==dis[u]+w&&c) { ll res=dfs(v,min(c,mf)); cost+=w*res; e[i].c-=res; e[i^1].c+=res; mf-=res; sm+=res; if(mf==0)break; } } if(sm==0)dis[u]=inf; return sm; } void dinic() { ll flow=0; while(SPFA()) { memcpy(cur,h,sizeof(h)); vis.reset(); flow+=dfs(s,inf); } } int main() { //freopen("sample.in","r",stdin); //freopen("sample.out","w",stdout); ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>m; s=n*m*2+1,t=n*m*2+2; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { char c; cin>>c; for(int k=0;k<4;k++) { int w=1,tx=i,ty=j; getpos(tx,ty,k); if(c=='D'&&k==0)w=0; if(c=='U'&&k==1)w=0; if(c=='R'&&k==2)w=0; if(c=='L'&&k==3)w=0; addeg(getid(i,j,0),getid(tx,ty,1),1,w); } addeg(s,getid(i,j,0),1,0); addeg(getid(i,j,1),t,1,0); } } dinic(); cout<<cost; return 0; }
- 1
信息
- ID
- 4836
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者