本题是典型的判断正圈的问题,很直接就想到用spfa,和bellman_ford来做,但是没想到可以用floyd来做,比较三种做法,spfa最快,bellman_ford最慢;但也只比floyd慢10多毫秒左右,如果用scanf的话还要更快,下面给出三种解法
spfa:
#include<cstdio>
#include<queue>
#include<stack>
#include<cstring>
#include<map>
#include<string>
#include<iostream>
using namespace std;
const int maxn=100+10;
const int N=6000;
const int INF=10000000;
int vis[maxn],head[maxn],len,n;
double dis[maxn];
int count[maxn];//记录一个点入队列的次数
struct node{
int a,b,next;
double c;
}p[N];
map<string,int> m;
void add(int a,int b,double c)
{
p[len].b=b;
p[len].c=c;
p[len].next=head[a];
head[a]=len++;
}
bool spfa(int x)
{
stack<int> q;
q.push(x);
dis[x]=1;
vis[x]=1;
count[x]++;
while(!q.empty())
{
int u=q.top();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=p[i].next)
{
int v=p[i].b;
if(dis[v]<dis[u]*p[i].c)
{
dis[v]=dis[u]*p[i].c;
// cout<<dis[v]<<endl;
if(vis[v]) continue;
vis[v]=1;
count[v]++;
q.push(v);
if(count[v]>=n)//图中有正环
return true;
}
}
}
return false;
}
void init()
{
len=0;
for(int i=1;i<=n;++i)
{
count[i]=0;
dis[i]=0;
vis[i]=0;
}
memset(head,-1,sizeof(head));
}
int main()
{
int i,j,m1,cnt=0;
string str1,str2;
//freopen("I.txt","r",stdin);
while(cin>>n)
{
if(n==0)
break;
init();
for(i=1;i<=n;i++)
{
cin>>str1;
m[str1]=i;
}
cin>>m1;
while(m1--)
{
double x;
cin>>str1>>x>>str2;
i=m[str1],j=m[str2];
add(i,j,x);
}
if(spfa(1))
printf("Case %d: Yes\n",++cnt);
else
printf("Case %d: No\n",++cnt);
}
}
bellman_ford
#include<cstdio>
#include<queue>
#include<stack>
#include<cstring>
#include<map>
#include<string>
#include<iostream>
using namespace std;
const int maxn=100+10;
const int N=6000;
const int INF=10000000;
int vis[maxn],head[maxn],len,n;
double dis[maxn];
int count[maxn];//记录一个点入队列的次数
struct node{
int a,b,next;
double c;
}p[N];
map<string,int> m;
void add(int a,int b,double c)
{
p[len].a=a;
p[len].b=b;
p[len++].c=c;
}
bool bellman_ford(int x)
{
dis[x]=1;
for(int i=1;i<n;i++)
{
bool flag=false;
for(int j=0;j<len;j++)
{
//cout<<"here"<<endl;
int u=p[j].a,v=p[j].b;
double c=p[j].c;
if(dis[u]<dis[v]*c)
{
dis[u]=dis[v]*c;
//cout<<dis[u]<<endl;
flag=true;
}
}
if(!flag)
break;
}
for(int i=0;i<len;i++)
if(dis[p[i].a]<dis[p[i].b]*p[i].c)
return true;
return false;
}
void init()
{
len=0;
for(int i=1;i<=n;++i)
{
count[i]=0;
dis[i]=0;
vis[i]=0;
}
memset(head,-1,sizeof(head));
}
int main()
{
int i,j,m1,cnt=0;
string str1,str2;
//freopen("I.txt","r",stdin);
while(cin>>n)
{
if(n==0)
break;
init();
for(i=1;i<=n;i++)
{
cin>>str1;
m[str1]=i;
}
cin>>m1;
while(m1--)
{
double x;
cin>>str1>>x>>str2;
i=m[str1],j=m[str2];
add(i,j,x);
}
if(bellman_ford(1))
printf("Case %d: Yes\n",++cnt);
else
printf("Case %d: No\n",++cnt);
}
}
floyd
#include<cstdio>
#include<map>
#include<iostream>
using namespace std;
const int maxn=100+10;
const int N=6000;
const int INF=10000000;
double p[maxn][maxn];
map<string,int> m;
int n;
bool floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
//cout<<"here"<<endl;
if(p[i][j]<p[i][k]*p[k][j])
p[i][j]=p[i][k]*p[k][j];
}
for(int i=1;i<=n;i++)
if(p[i][i]>1.0)
return true;
return false;
}
void init()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
p[i][j]=i==j?0:INF;
}
}
int main()
{
int i,j,m1,cnt=0;
string str1,str2;
//freopen("I.txt","r",stdin);
while(cin>>n)
{
if(n==0)
break;
init();
for(i=1;i<=n;i++)
{
cin>>str1;
m[str1]=i;
}
cin>>m1;
while(m1--)
{
double x;
cin>>str1>>x>>str2;
i=m[str1],j=m[str2];
p[i][j]=x;
}
if(floyd())
printf("Case %d: Yes\n",++cnt);
else
printf("Case %d: No\n",++cnt);
}
}