bzoj 1774: [Usaco2009 Dec]Toll 过路费【排序+Floyd】

非常迷的一道题啊
我觉得挺对的版本只得了30
总之就是Floyd·改,开两个数组,一个是d[i][j]就是普通的只有边权的最短路,a[i][j]是题目要求的那种
具体改的地方是把枚举中转点的地方把中转点按从小到大的顺序枚举,d[i][j]按照套路更新即可,然后a[i][j]从a[i][j]原数和d[i][j]+max(c[i],c[j],c[中转点])中取min
证明的话是最短路不一定是最终答案,能更新这个答案的一定是最大点更小一些的另一条路,所以按点权顺序更新能保证把这种情况全部更新

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=255,inf=1e9+7;
int n,m,q,a[N][N],d[N][N],v[N];
struct qwe
{
	int p,v;
}c[N];
bool cmp(const qwe &x,const qwe &y)
{
	return x.v<y.v;
}
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
int main()
{
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;i++)
		v[i]=d[i][i]=a[i][i]=c[i].v=read(),c[i].p=i;
	sort(c+1,c+1+n,cmp);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(i!=j)
				a[i][j]=d[i][j]=inf;
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read(),z=read();
		d[x][y]=d[y][x]=min(d[x][y],z);
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				d[i][j]=min(d[i][j],d[i][c[k].p]+d[c[k].p][j]),a[i][j]=min(a[i][j],d[i][j]+max(max(v[i],v[j]),c[k].v));
	while(q--)
	{
		int x=read(),y=read();
		printf("%d\n",a[x][y]);
	}
	return 0;
}

我觉得挺对的版本:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=255,inf=1e9+7;
int n,m,q,a[N][N],c[N],mx[N][N];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int main()
{
    n=read(),m=read(),q=read();
    for(int i=1;i<=n;i++)
        c[i]=read(),mx[i][i]=a[i][i]=c[i];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j)
                a[i][j]=mx[i][j]=inf;
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read(),z=read();
        if(a[x][y]>z+max(c[x],c[y]))
            a[x][y]=a[y][x]=z+max(c[x],c[y]),mx[x][y]=mx[y][x]=max(c[x],c[y]);
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(a[i][j]>a[i][k]-mx[i][k]+a[k][j]-mx[k][j]+max(mx[i][k],mx[k][j]))
                    a[i][j]=a[i][k]-mx[i][k]+a[k][j]-mx[k][j]+max(mx[i][k],mx[k][j]),mx[i][j]=max(mx[i][k],mx[k][j]);
    while(q--)
    {
        int x=read(),y=read();
        printf("%d\n",a[x][y]);
    }
    return 0;
}
posted @ 2018-07-02 17:32  lokiii  阅读(159)  评论(0编辑  收藏  举报