From AtCoder

链接

考虑如何判断可行性。
对于 \(n\) 的排列 \(P=(p_1,p_2,...,p_n)\) ,不论如何操作,\(\sum\limits_{i=1}^{n} a_{i,p_i}\) 不变,若其最小值小于 \(0\) ,则不存在方案。对这个我们可以用 \(KM\) 算法求得(需用 \(bfs\) 版本的,\(dfs\) 与费用流会被卡)。
如果成立,我们可以求出这个排列,以后的操作只在 \(a_{i,p_i}\) 上进行,这样这些值是不会变的。
我们首先得让它们全都大于等于 \(0\) ,不难发现 \(n-1\) 次操作即可。
\(q_{p_i}=i\),在 \(a_{i,p_i}\) 上的操作值为 \(w_i\),对于 \(a_{i,j}\) ,则可得 \(w_{q_j} - w_{i} \leq a_{i,j}\) ,一个差分约束的形式。可以求出它们间的最短路,我们令 \(w_1=0\) ,对于 \(i \geq 2\) ,我们对 \(a_{i,p_i}\) 的操作量为 \(1\)\(i\) 的最短路长度。
这样构造是 \(n \cdot 2-2\) 次的,复杂度 \(O(n^3)\) ,可以通过。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define IL inline
#define LL long long
using namespace std;
const int N=503,inf=0x3f3f3f3f;
int n,m,w[N][N],vis[N],slack[N],vx[N],vy[N],mat[N],pre[N],ans[N],f[N][N];
IL int in(){
	char c;int f=1;
	while((c=getchar())<'0'||c>'9')
	  if(c=='-') f=-1;
	int x=c-'0';
	while((c=getchar())>='0'&&c<='9')
	  x=x*10+c-'0';
	return x*f;
}
void bfs(int s){
	memset(vis,0,sizeof(vis));
	memset(pre,0,sizeof(pre));
	memset(slack,63,sizeof(slack));
	int px=s,py=0,Min,pos;mat[py]=px;
	while(mat[py]){
		px=mat[py],Min=inf,vis[py]=1;
		for(int i=1;i<=n;++i)
		  if(!vis[i]){
		  	if(slack[i]>vx[px]+vy[i]-w[px][i]) slack[i]=vx[px]+vy[i]-w[px][i],pre[i]=py;
		  	if(slack[i]<Min) Min=slack[i],pos=i;
		  }
		for(int i=0;i<=n;++i)
		  if(vis[i]) vx[mat[i]]-=Min,vy[i]+=Min;
		  else slack[i]-=Min;
		py=pos;
	}
	while(py) mat[py]=mat[pre[py]],py=pre[py];
}
int KM(){
	memset(vx,0,sizeof(vx)),
	memset(vy,0,sizeof(vy)),
	memset(mat,0,sizeof(mat));
	for(int i=1;i<=n;++i) bfs(i);
	int val=0;
	for(int i=1;i<=n;++i) val+=vx[i]+vy[i];
	for(int i=1;i<=n;++i) ans[mat[i]]=i;
	return val;
}
void print(int x,int y,int z){printf("%d %d %d\n",x,y,z);}
int main()
{
	int x,y;
	n=in();
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    w[i][j]=-in();
	if(KM()>0) return cout<<-1<<endl,0;
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    w[i][j]=-w[i][j];
	printf("%d\n",2*n-2);
	for(int i=1;i<n;++i){
		print(n,ans[i],w[i][ans[i]]);
		int val=w[i][ans[i]];
		for(int j=1;j<=n;++j)
		  w[n][j]+=val,w[j][ans[i]]-=val;
	}
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    if(i^j) f[i][j]=w[i][ans[j]];
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    for(int k=1;k<=n;++k)
	      f[j][k]=min(f[j][k],f[j][i]+f[i][k]);
	for(int i=2;i<=n;++i) print(i,ans[i],f[1][i]);
	return 0;
}
posted @ 2022-08-07 23:33  (o-ωq)).oO  阅读(16)  评论(0编辑  收藏  举报