1 条题解
-
0
来一个瞎几把口胡的费用流做法首先每个点向目标点连边,显然是一个二分图完备匹配。
然后显然直接跑 MCMF 是会寄掉的。
不妨来想一想怎么让费用流模型帮我们“自动”计算费用。
因为绕着一个环的那个绝对值的最小值相当于最短路,所以我们可以对于每个桌子,连一条边 (最坏有 个节点会经过这条边)
然后在桌子与桌子之间连边。
具体地
对于 个位置,每个位置连每张桌子上对应的位置
每个桌子内部有 条边。
节点数量是 ,边数量是 。
也许是可以跑过去的。( 个点和 条边)
而且还有分层,边权也很有规律。。。
需要注意的是此图存在负环,需要处理一下细节。
好像数据有点儿水,直接跑就能过(
以及不知道为什么要把前向星换成 vector 才能过。
听说正解是把这个建图在连 的时候用线段树优化建图。(好像是说不这样的话不写 zkw 费用流过不去)
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-funroll-loops","-fdelete-null-pointer-checks") #include<cstdio> #include<vector> #include<queue> const int M=305,N=15; int n,m,s,t,tot,l[M][N],r[M][N],in[M][N],out[M][N]; int d[6005];bool iq[6005],vis[6005]; std::deque<int>q;int flow,ret; inline int min(const int&a,const int&b){return a>b?b:a;} inline int abs(const int&a){return a>0?a:-a;} struct Edge{ int v,w,flow,id; };std::vector<Edge>G[6005]; inline void Add(const int&u,const int&v,const int&flow,const int&w){ G[u].push_back((Edge){v,w,flow,G[v].size()}); G[v].push_back((Edge){u,-w,0,G[u].size()-1}); } inline bool BFS(){ for(int i=s;i<=t;++i)d[i]=0x7fffffff,vis[i]=false;d[s]=0;q.push_back(s); while(!q.empty()){ const int u=q.front();int v;iq[u]=false;q.pop_front(); for(Edge&E:G[u])if(E.flow){ const int&w=d[u]+E.w; if(w<d[v=E.v]){ d[v]=w;if(iq[v])continue;iq[v]=true; if(!q.empty()&&d[v]<d[q.front()])q.push_front(v);else q.push_back(v); } } } return d[t]!=0x7fffffff; } inline int DFS(const int&u,const int&flow){ if(u==t)return flow; int v,ret(flow);vis[u]=true; for(Edge&E:G[u])if(d[v=E.v]==d[u]+E.w&&E.flow&&!vis[v]){ const int&F=DFS(v,min(ret,E.flow));if(!F)d[v]=-0x7fffffff;E.flow-=F;G[v][E.id].flow+=F;ret-=F; if(!ret)return flow; } return flow-ret; } inline void Dinic(){ while(BFS())while(const int&F=DFS(s,n*m))ret+=F*d[t],flow+=F; if(flow!=n*m)printf("no solution");else printf("%d",ret); } signed main(){ scanf("%d%d",&n,&m); s=++tot;for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",l[i]+j),++l[i][j],in[i][j]=++tot; for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",r[i]+j),++r[i][j],out[i][j]=++tot;t=++tot; for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){ Add(s,in[i][j],1,0);Add(out[i][j],t,1,0);Add(out[i][j],out[i][j%m+1],m,1);Add(out[i][j%m+1],out[i][j],m,1); for(int k=l[i][j];k<=r[i][j];++k)Add(in[i][j],out[k][j],1,abs(i-k)<<1); } Dinic(); }
- 1
信息
- ID
- 10781
- 时间
- 5000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者