UVA 1416 Warfare And Logistics 迪杰斯特拉算法

UVA 1416

题意:给一个n个节点m条边的无向图,求每个点到所有点的最短距离之和,如n=3时,答案是c=d[1][2]+d[1][3]+d[2][1]+       d[2][3]+d[3][1]+d[3][2],不联通的两点距离为L,还要求删除一条边后的最大的c'。

思路:每次dij()算法求出每个点到所有点的最短距离和,有n个点,复杂度nmlogn,还需要删除每条边再求这么多c',复杂度为nm^2logn,复杂度太高,但是每次求出某点到所有点的的最短距离和之后,可以把这颗最短路树的边标记,下次删除边时,只有删除n-1个边,因为删除其他边,求该点的最短路和等于没删边的值,这样下来复杂度为mn^2logn,不过有个巨大的坑,题目说不联通的两点距离为L,因此在开始的时候就要把所有未直接连通的两点加一条权值为L的边。

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=105;
typedef long long LL;
const LL inf=1e14;
struct node
{
	int u,num;//num为边的编号 
	long long dist;
	bool friend operator<(node c,node d)
	{
		return c.dist>d.dist;
	}
}no,ne;
vector<node>G[maxn];
int vis[maxn],vis1[11100],link[maxn][maxn];
LL d[maxn],c[maxn][11100],ans1,ans2,L;
int n,m,tot;
void init()
{
	for(int i=1;i<=n;i++)
	{
		G[i].clear();
		memset(link[i],0,sizeof(link[i]));
	}
	
	ans1=ans2=0; 
}
LL dij(int s,int flag)
{
	for(int i=1;i<=n;i++)
	{
		vis[i]=0;
		d[i]=inf;
	}
	priority_queue<node>q;
	no.u=s,no.dist=0;
	q.push(no);
	d[s]=0;
	while(!q.empty())
	{
		no=q.top();q.pop();
		if(vis[no.u])
		continue;
		vis[no.u]=1;
		if(flag==0&&no.u!=s)
		vis1[no.num]=1;//标记最短路树的边 
		int u=no.u;
		for(int i=0;i<G[u].size();i++)
		{
			int v=G[u][i].u;
			LL tmp=G[u][i].dist;
			if(G[u][i].num==flag)//要删除的边 
			tmp=L;
			if(d[v]>d[u]+tmp)
			{
				d[v]=d[u]+tmp;
				ne.dist=d[v];
				ne.num=G[u][i].num;
				ne.u=v;
				q.push(ne);
			}
		}
	}
	LL sum=0;
	for(int i=1;i<=n;i++)
	sum+=d[i];
	return sum;
}
void work()
{
	for(int i=1;i<=n;i++)
	{
		memset(vis1,0,sizeof(vis1));
		LL t=dij(i,0);
		ans1+=t;
		for(int j=1;j<=tot;j++)
		c[i][j]=t;
		for(int j=1;j<=tot;j++)
		if(vis1[j]==1)
		c[i][j]=dij(i,j);
	}
	for(int i=1;i<=tot;i++)
	{
		LL sum=0;
		for(int j=1;j<=n;j++)
		sum+=c[j][i];
		ans2=max(ans2,sum);
	}
}
int main()
{
	int u,v;
	LL len;
	while(~scanf("%d%d%lld",&n,&m,&L))
	{
		init();
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%lld",&u,&v,&len);
			no.u=u,no.num=i,no.dist=len;
			G[v].push_back(no);
			no.u=v,no.num=i,no.dist=len;
			G[u].push_back(no);
			link[u][v]=link[v][u]=1;
		}
		tot=m;
		for(int i=1;i<=n;i++)
		{
			
			for(int j=i+1;j<=n;j++)//补边 
			{
				if(link[i][j]==1)
				continue;
				no.u=j,no.num=++tot,no.dist=L;
				G[i].push_back(no);
				no.u=i,no.num=tot,no.dist=L;
				G[j].push_back(no);
			}
		}
		work();
		printf("%lld %lld\n",ans1,ans2);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值