題意:有向有負權圖,加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;
}