Description
A long time ago, 有一个国家有n 座从0 到n-1编号的城市。城市0 是首都。国家道路网络形成了一个无向连通图。换句话说:某些对城市被双向通行的道路所连接。
对于每座城市,可以从城市出发经过一系列连续的道路到达首都。(当两条道路需要在城市外相交时,相交处总是会有一座桥梁,因此城市外并没有路口。)
你会获得一个用于描述道路网络的字符矩阵linked。对于每个i 和j,当城市i 和城市j 已由一条道路直接连通时linked[i][j] 为‘Y’ ,否则为‘N’ 。
两个城市间的距离为从一个城市到达另一个城市所需通过的道路的最小数目。居住在首都以外的市民通常都对他们与首都之间的距离不爽。因此你会获得一个n 个元素的数组want。对于每个i,want[i] 是城市i 与首都之间的市民
期望距离。
福克斯· 夏尔正在负责建造新的道路。每个新道路必须双向且连接两座城市。一旦所有的新道路落成,市民们会计算他们对最终道路网络的不爽值:
对于每个i:令real[i] 为从城市i 到达首都的新距离。那么城市i 的市民增加的对国家的不爽值为(want[i]-real[i])^2。
计算并回答夏尔建造一些(可能是零)新道路之后新增不爽值之和的最小值。
Solution
题目的要求就是求出一个序列,使得在满足:有直接连边的两数差不超过1;的情况下,使得代价最小。
这题的正解很暴力,用最小割;
首先对于每个点,构出n个点,第i点表当这个点数值为i的情况,有以下几种连线:
1. 第i-1个向第i个连权值为(当这个点值为i时的代价),第1个被S连,最后一个向T连正无穷;
2. 第i个向第i-1个连正无穷;(因为在最后的图中,如果i能被S流到,那么i-1也一定要能够)
3. 对于在原图中有直接连边的a,b,因为它们的值差不能超过1,所以当最后的值是
Va>Vb
时,对于所有的k,如果a的第k个点能被S流到,那么b的k-1及以下的都要被S流到,所有a的第k个向b的第k-1个连正无穷;当
Va<Vb
则反之。
连完以后直接跑最小割出来的值就是Ans了
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define BH(i,q) ((i)*n-n+(q)+1)
#define sqr(q) ((q)*(q))
using namespace std;
const int N=3000,INF=1e9;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans,S,T;
int B[N*N][3],A[N],B0=1;
int Hv[N],H[N];
void link(int q,int w,int e,int e1)
{
if(e==0&&e1==0)return;
B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w,B[B0][2]=e;
B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q,B[B0][2]=e1;
}
int aug(int q,int e)
{
if(q==T)return e;
int mi=T+2;
efo(i,q)if(B[i][2])
{
if(H[B[i][1]]+1==H[q])
{
int t=aug(B[i][1],min(e,B[i][2]));
if(t)
{
B[i][2]-=t;
B[i^1][2]+=t;
return t;
}
}
mi=min(mi,H[B[i][1]]);
if(H[S]>T+1)return 0;
}
if(!(--Hv[H[q]]))H[S]=T+3;
Hv[H[q]=mi+1]++;
return 0;
}
int main()
{
freopen("fox.in","r",stdin);
freopen("fox.out","w",stdout);
int q,w;
while(scanf("%d",&n)!=EOF)
{
B0=1;
S=0;T=n*n+1;
fo(i,S,T)A[i]=0;
link(BH(1,n-1),T,INF,0);
fo(i,2,n)link(S,BH(i,0),INF,0),link(BH(i,n-1),T,INF,0);
fo(i,1,n)
{
char ch=' ';
while(ch!='Y'&&ch!='N')ch=getchar();
fo(j,1,n)
{
if(ch=='Y')
{
fo(k,1,n-1)
link(BH(i,k),BH(j,k-1),INF,0);
}
ch=getchar();
}
}
fo(i,1,n)
{
read(q);
fo(k,0,n-2)link(BH(i,k),BH(i,k+1),(i==1?INF:sqr(q-k-1)),0);
}
ans=0;
fo(i,S,T+10)H[i]=Hv[i]=0;
Hv[0]=T+1;
while(H[S]<T+2)ans+=aug(S,INF);
printf("%d\n",ans);
}
return 0;
}