2019 南京網絡賽 H Holy Grail(二分+spfa判負環模板)

 

題意:有向有負權圖,加6條邊,求每次最小的邊權,使圖沒有負環,答案唯一。

思路:二分答案+spfa判負環

1.dfs判負環 16ms

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int N=310,M=550;
const ll inf=0x3f3f3f3f3f3f3f3f;
int head[N],ver[M],nt[M];
ll edge[M];
bool ha[N];
int n,m,tot;
int x,y;
ll z;
ll dis[N];
void add(int x,int y,ll z)
{
    ver[++tot]=y,edge[tot]=z;
    nt[tot]=head[x],head[x]=tot;
}
//有負環返回false,無負環返回true 
bool SPFA(int x)
{
   ha[x]=true;
   for(int i=head[x];i!=-1;i=nt[i])
   {	
       int y=ver[i];
	   ll z=edge[i];
       if(dis[y]>dis[x]+z)
       {
           dis[y]=dis[x]+z;
           if(ha[y]) return false; 
           if(!SPFA(y)) return false;
       }
   }
   ha[x]=false;
   return true; 
}
int main(void)
{
	int t,tt=0;
	scanf("%d",&t);
	while(t--)
	{
    	tot=0;
	    memset(head,-1,sizeof(head));
	    scanf("%d%d",&n,&m);
	    for(int i=1;i<=m;i++)
	    {
	        scanf("%d%d%lld",&x,&y,&z);
	        add(x,y,z);
	    }
	    for(int i=1;i<=6;i++)
	    {
	    	scanf("%d%d",&x,&y);
	    	add(x,y,0); 
	    	ll l,r,mid,ans=1e9;
	    	l=-4e9,r=2e9;	
	    	while(l<=r)
	    	{
	    		mid=(l+r)>>1;	 
				edge[tot]=mid;   		
	    		memset(ha,0,sizeof(ha));
	    		memset(dis,inf,sizeof(dis));
			    bool flag=false;
			    for(int i=0;i<n;i++)
			        if(!SPFA(i))
			        {
			            flag=true;
			            break;
			        }
			    if(flag)
			    	l=mid+1;	
				else
					ans=mid,r=mid-1;
	
			}
			printf("%lld\n",ans);
    		edge[tot]=ans;
		}	
	}
	
    return 0;
}

2.bfs+不標記次數 201ms

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
const int N = 310;
const int M = 550;
const ll inf=0x3f3f3f3f3f3f3f3f;
struct node
{
	int to,nxt;
	ll d;
}g[M];
int head[N],cnt,book[N],vis[N];
ll dis[N],l,r,mid,ans,d;
bool flag;
int n,m,u,v;
void Init()
{
	memset(head,-1,sizeof(head));
	cnt=0;	
}
void add(int u,int v,ll d)
{
	g[cnt].to=v;
	g[cnt].nxt=head[u];
	g[cnt].d=d;
	head[u]=cnt++;	
}

bool spfa()
{
  	queue<int> q;
  	int tot=0; 
  	for(int i=0;i<n;i++)
  	{
  		vis[i]=1,dis[i]=0;
		q.push(i),q.push(tot);	
	}
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		tot=q.front();
		q.pop();
		if(tot>=n) 
			return 1;
		vis[u]=0;
		for(int i=head[u];i!=-1;i=g[i].nxt)
		{
            v=g[i].to;
			if(dis[v]>dis[u]+g[i].d)
			{
				dis[v]=dis[u]+g[i].d;
			    if(!vis[v])	
				{
					q.push(v);
					q.push(tot+1);
					vis[v]=1;
				}
			}			
			
		}
		
	}
	return 0;
	
}
int main()
{
   int t;
   scanf("%d",&t);
   while(t--)
   {
	   	scanf("%d%d",&n,&m);
	   	Init();
	   	while(m--)
	   	{
	   	   scanf("%d%d%lld",&u,&v,&d);
		   add(u,v,d);	    	
		}
		for(int i=1;i<=6;i++)
		{
			scanf("%d%d",&u,&v);
			add(u,v,0);
			l=-4e9,r=2e9,ans=1e9;
			while(l<=r)
			{
				mid=(l+r)>>1;
				g[cnt-1].d=mid;
				if(spfa())
					l=mid+1;
				else
					ans=mid,r=mid-1;
			}
			printf("%lld\n",ans);
			g[cnt-1].d=ans;
		}
   }
   return 0;
}

3.bfs+標記次數 269ms

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
const int N = 310;
const int M = 550;
const ll inf=0x3f3f3f3f3f3f3f3f;
struct node
{
	int to,nxt;
	ll d;
}g[M];
int head[N],cnt,book[N],vis[N];
ll dis[N],l,r,mid,ans,d;
bool flag;
int n,m,u,v;
void Init()
{
	memset(head,-1,sizeof(head));
	cnt=0;	
}
void add(int u,int v,ll d)
{
	g[cnt].to=v;
	g[cnt].nxt=head[u];
	g[cnt].d=d;
	head[u]=cnt++;	
}

bool spfa()
{
	queue<int> q;
  	for(int i=0;i<n;i++)
  		book[i]=vis[i]=1,dis[i]=0,q.push(i);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];~i;i=g[i].nxt)
		{
            v=g[i].to;
			if(dis[v]>dis[u]+g[i].d)
			{
				dis[v]=dis[u]+g[i].d;
			    if(!vis[v])	
				{
					book[v]++;
					if(book[v]>=n)
						return 1;
					q.push(v);
					vis[v]=1;
				}
			}				
		}	
	}
	return 0;	
}
int main()
{
   int t;
   scanf("%d",&t);
   while(t--)
   {
	   	scanf("%d%d",&n,&m);
	   	Init();
	   	while(m--)
	   	{
	   	   scanf("%d%d%lld",&u,&v,&d);
		   add(u,v,d);	    	
		}
		for(int i=1;i<=6;i++)
		{
			scanf("%d%d",&u,&v);
			add(u,v,0);
			l=-4e9,r=2e9,ans=1e9;
			while(l<=r)
			{
				mid=(l+r)>>1;
				g[cnt-1].d=mid;
				if(spfa())
					l=mid+1;
				else
					ans=mid,r=mid-1;
			}
			printf("%lld\n",ans);
			g[cnt-1].d=ans;
		}
   }
   return 0;
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章