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;
}