【图论】2015 Multi-University Training Contest 1 1007

本文讨论了使用SPFA算法解决无向图最短路径问题,并通过实例展示了算法的应用,包括构建最短路图、求最小割及特殊条件下的路径长度计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这也是这次多校相对比较简单的一道题。

对于一个无向图,正向spfa一遍,反向spfa一遍,然后求出它的最短路图,我的最短路图把方向也构建了出来,然后第一问只需要求一个最小割就行,第二问的话就把最短路图的边长全部赋为1然后再跑一遍spfa就可以。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

struct rec
{
	int dis,num,w,next;
}e[5][151000];
struct rec2
{
	int v,u,w;
}v[151000];
int n,m;
int link[5][3010],dist[5][3010],e_tot[5];

void insert(int x,int y,int z,int w)
{
	if (w==1) 
	{
		e_tot[w]++;e[w][e_tot[w]].num=y;e[w][e_tot[w]].w=z;e[w][e_tot[w]].next=link[w][x];link[w][x]=e_tot[w];
	}
	if (w==2)
	{
		e_tot[w]++;e[w][e_tot[w]].num=y;e[w][e_tot[w]].w=z;e[w][e_tot[w]].next=link[w][x];e[w][e_tot[w]].dis=e_tot[w]+1;
		link[w][x]=e_tot[w];
		e_tot[w]++;e[w][e_tot[w]].num=x;e[w][e_tot[w]].w=0;e[w][e_tot[w]].next=link[w][y];e[w][e_tot[w]].dis=e_tot[w]-1;
		link[w][y]=e_tot[w];
		e_tot[w+1]++;e[w+1][e_tot[w+1]].num=y;e[w+1][e_tot[w+1]].w=1;e[w+1][e_tot[w+1]].next=link[w+1][x];
		link[w+1][x]=e_tot[w+1];
	}
}
int head,tail;
int dui[2100];
bool flag[2100];
void spfa(int x,int w,int ww)
{
	memset(flag,0,sizeof(flag));
	head=0;
	tail=1;
	dui[tail]=x;
	dist[w][x]=0;
	flag[x]=1;
	while(head!=tail){
		head=(head+1)%(n+1);
		int xx=dui[head];
		for (int p=link[ww][xx];p;p=e[ww][p].next){
			int j=e[ww][p].num;
			if(dist[w][j]>dist[w][xx]+e[ww][p].w){
				dist[w][j]=dist[w][xx]+e[ww][p].w;
				if(!flag[j]){
					flag[j]=1;
					tail=(tail+1)%(n+1);
					dui[tail]=j;
				}
			}
		}
		flag[xx]=0;
	}
}
void make_net()
{
	for (int i=1;i<=m;i++)
		if ((dist[1][v[i].u]+dist[2][v[i].v]+v[i].w==dist[1][n])||(dist[1][v[i].v]+dist[2][v[i].u]+v[i].w==dist[1][n]))
		{
			if (dist[1][v[i].v]>dist[1][v[i].u]) insert(v[i].u,v[i].v,1,2);
			else insert(v[i].v,v[i].u,1,2);
		}
}
int h[3100],s[3100];
int dfs(int x,int total)
{
    if (x==n) return total;
    int minh=n-1,leave=total,w;
    for (int p=link[2][x];p;p=e[2][p].next)
    {
        //printf("%d %d %d %d\n",x,total,p,e[p].num);
        if (e[2][p].w>0)
        {
            if (h[x]==h[e[2][p].num]+1)
            {
                w=dfs(e[2][p].num,min(e[2][p].w,leave));
                e[2][p].w-=w;
                e[2][e[2][p].dis].w+=w;
                leave-=w;
                if (h[1]==n) return total-leave;
            }
            minh=min(h[e[2][p].num],minh);
        }
    }
    if (leave==total)
    {
        s[h[x]]--;
        if (s[h[x]]==0)
            h[1]=n;
        h[x]=minh+1;
        s[h[x]]++; 
    }
    return total-leave;
}
void network()
{
	int ans=0;
	memset(h,0,sizeof(h));
	memset(s,0,sizeof(s));
	s[0]=n;
	while (h[1]<n) 
		ans+=dfs(1,200000000);
	printf("%d ",ans);
}
void clean()
{
	memset(dist,30,sizeof(dist));
	memset(e,0,sizeof(e));
	memset(link,0,sizeof(link));
	memset(v,0,sizeof(v));
	memset(e_tot,0,sizeof(e_tot));
}
int main()
{
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	while (scanf("%d%d",&n,&m)!=EOF)
	{
		clean();
		for (int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&v[i].u,&v[i].v,&v[i].w);
			insert(v[i].u,v[i].v,v[i].w,1);
			insert(v[i].v,v[i].u,v[i].w,1);
		}
		spfa(1,1,1);
		spfa(n,2,1);
		make_net();
		network();
		spfa(1,3,3);
		printf("%d\n",m-dist[3][n]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值