【Srm590】Fox And City(fox)

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。

计算并回答夏尔建造一些(可能是零)新道路之后新增不爽值之和的最小值。

Input

多组数据,读入到文件结束。

每组数据第一行,一个整数n——夏尔的国家内的城市数量。

接下来n 行,描述字符矩阵linked。第i 行第j 列的字符为linked[i][j]。

字符矩阵之后还有单独一行的n 个整数,为期望距离数组want。

Output

对于每组数据,输出单独一行一个整数——夏尔的最优方案中新道路都落成之后市民们新增的不爽值的最小值。

Sample Input

3
NYN
YNY
NYN
0 1 1
4
NYNN
YNYN
NYNY
NNYN
0 3 3 3
6
NYNNNY
YNYNNN
NYNYNN
NNYNYN
NNNYNY
YNNNYN
0 2 2 2 2 2
3
NYY
YNN
YNN
0 0 0
6
NYNNNN
YNYNNN
NYNYYY
NNYNYY
NNYYNY
NNYYYN
0 1 2 3 0 3
6
NYNNNN
YNYNNN
NYNYYY
NNYNYY
NNYYNY
NNYYYN
0 1 2 4 0 4
11
NYNYYYYYYYY
YNYNNYYNYYY
NYNNNYYNYYN
YNNNYYYYYYY
YNNYNYYYNYY
YYYYYNNYYNY
YYYYYNNNYYY
YNNYYYNNNYY
YYYYNYYNNNY
YYYYYNYYNNY
YYNYYYYYYYN
0 1 2 0 0 5 1 3 0 2 3

Sample Output

0
5
2
2
3
6
28

【样例解释】

第一组数据:夏尔可以建造一条连接城市0 和城市2 的道路。然后有real[1] = 1; real[2] = 1,并且总不爽值为零。

第二组数据:最优方案是不建造新道路。然后总不爽值将会为(3-1)^2+(3-2)^2+ (3-3)^2 = 5。

第三组数据:最优方案中的一种是,在城市1 和城市3 之间建造一条新道路。

Data Constraint

对于30% 的数据,能够新增的不同的道路的数量不超过16 条,数据组数<=10。

对于100% 的数据满足:

数据组<=15。

2<= n <=40; 0 <=want[i] < n;want[0] = 0。

对于所有的i 和j,有linked[i][j] = linked[j][i]

对于所有的i,有linked[i][i] =’ N’

Solution

这种题说什么好呢?
求最小值启示我们用最小割
设dis[i]表示i与0号点的距离
设point(i,j)表示状态dis[i]<=j,如果归为S集,表示dis[i]>j否则表示dis[i]<=j
考虑几种情况
1.S向所有point(i,0)连INF,因为除了0号点,所有点的dis不可能为0
2.所有point(i,n-1)向T连INF,因为所有点的dis都不可能大于n-1
3.所有point(i,k)向point(i,k+1)连 (k+1want[i])2 的边,因为这表示dis[i]=k+1,并把这两个点分到两个集合中
4.所有point(i,k)向point(i,k-1)连INF,因为不可能有dis[i]>k而

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 1700
#define INF 214748347
#define sqr(x) ((x)*(x))
#define po(i,j) ((((i)-1)*n+(j))+1)
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
int S,T,n,want[N],last[N],next[N*1000],data[N*1000],to[N*1000],tot=1,d[N],bz[N];
void putin(int x,int y,int z)
{
    next[++tot]=last[x];last[x]=tot;to[tot]=y;data[tot]=z;
    next[++tot]=last[y];last[y]=tot;to[tot]=x;data[tot]=0;
}
bool bfs()
{
    int i=0,j=1;cl(bz); 
    bz[d[1]=S]=1;
    while(i<j)
    {
        int x=d[++i];
        for(int k=last[x];k;k=next[k])
        {
            int y=to[k];
            if(!bz[y]&&data[k]>0) bz[y]=bz[x]+1,d[++j]=y;
        }
    }
    return bz[T];
}
int dfs(int x,int t)
{
    if(x==T) return t;
    int ans=0;
    for(int k=last[x];k;k=next[k])
    {
        int y=to[k];
        if(bz[y]!=bz[x]+1||data[k]<=0) continue;
        int jy=dfs(y,min(t,data[k]));
        if(jy) data[k]-=jy,data[k^1]+=jy,ans+=jy,t-=jy;
        if(t==0) break;
    }
    if(ans==0) bz[x]=-1;
    return ans;
}
int main()
{
    freopen("fox.in","r",stdin);
    freopen("fox.out","w",stdout);
    while(scanf("%d\n",&n)!=EOF)
    {
        S=n*n+1;T=n*n+2;tot=1;cl(last);
        scanf("\n");
        fo(i,1,n)
        {
            if(i!=1) putin(S,po(i,0),INF);
            putin(po(i,n-1),T,INF);
            fo(k,1,n-1) putin(po(i,k),po(i,k-1),INF);   
            fo(j,1,n)
            {
                char ch;scanf("%c",&ch);
                if(ch=='Y')
                {
                    fo(k,1,n-1) putin(po(i,k),po(j,k-1),INF),putin(po(j,k),po(i,k-1),INF);
                }
            }
            scanf("\n");
        }
        fo(i,1,n) scanf("%d",&want[i]);
        fo(i,2,n) fo(k,0,n-2) putin(po(i,k),po(i,k+1),sqr(k+1-want[i]));
        fo(k,0,n-2) putin(po(1,k),po(1,k+1),INF);
        int ans=0;
        while(bfs()) ans+=dfs(S,INF);
        printf("%d\n",ans);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值