题意:
题面70%的都是废话,还有很多影响读题的条件...
其实就是给你一个有向图,问你这个有向图里面存不存在环,使得组成环的边的权值的总乘积>1
有输出"inadmissiable",否则输出"admissiable"
解析:
这道题其实就是一道spfa判负权环的题目,找最长路。
但是这里的小数很难处理,因为有4位小数,并且还有5000条边,乘积的话数据的数值和精度都会达到非常大
这里就有了神奇的log函数,可以使得乘法变成加法,除法变成减法,并且大小的相对顺序还不会发生改变
#include<vector>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;
#define pb push_back
typedef long long int ll;
typedef long double LD;
#define MAXN 900
#define INF 0x3f3f3f3f
const ll MOD =1000000007;
typedef struct node
{
int v;
LD w;
node(int vv,LD ww):v(vv),w(ww){}
}node;
vector<node> edge[MAXN];
int n;
int vis[MAXN];
LD d[MAXN];
int r[MAXN]; //入队次数,如果一个点入队次数>=n,那么存在负环
int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
queue<int> q;
int spfa(int src)
{
while(!q.empty()) q.pop();
for(int i=0;i<=n;i++) d[i]=-INF,vis[i]=0,r[i]=0;
d[src]=0;
q.push(src);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=0;i<edge[u].size();i++)
{
node x=edge[u][i];
LD tmp=d[u]+x.w;
//if(x.v==src&&tmp>d[src]) return 1;
if(d[x.v]<tmp)
{
d[x.v]=tmp;
if(!vis[x.v])
{
r[x.v]++;
vis[x.v]=1;
q.push(x.v);
}
}
if(r[x.v]>=n) return 1; //有环
}
}
return 0;
}
int main()
{
int m;
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;
LD w;
scanf("%d%d%Lf",&u,&v,&w);
edge[u].push_back(node(v,log(w)));
}
//for(int i=1;i<=n;i++) r[i]=0;
int flag=0;
for(int i=1;i<=n;i++)
{
{
flag=spfa(i);
if(flag) break;
}
}
if(flag) printf("inadmissible\n");
else printf("admissible\n");
return 0;
}
用bellman-Ford判负环也可以
代码来源Reconquista
#include <bits/stdc++.h>
using namespace std;
#define N 5010
int a[N], b[N];
long double c[N], d[N];
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++i)
{
scanf("%d %d", &a[i], &b[i]);
double w;
scanf("%lf", &w);
c[i] = log(w);
}
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
d[b[j]] = max(d[b[j]], d[a[j]] + c[j]);
}
}
int flag = 0;
for (int i = 1; i <= m; ++i)
{
if (d[b[i]] < d[a[i]] + c[i])
flag = 1;
}
puts(flag? "inadmissible": "admissible");
return 0;
}
然后下面就是我自己神奇的卡过方法.....
我发现这道题数据可能并没有卡你数值大小和精度,我直接用边相乘找最大路,判负环也过了。
一开始一直在WA,后来我把spfa判负环的条件改成了if(x.v==src&&tmp>d[src]) return 1;就成功卡过了。
这个可以的原因是,之前我是一个负环跑n边才判定找到。
这里不一样的是我是每一个点都跑一边spfa,那么对于每一个点,我只要找包含他的负环就可以了
#include<vector>
#include<queue>
#include<algorithm>
#include<cstdio>
using namespace std;
#define pb push_back
typedef long long int ll;
typedef long double LD;
#define MAXN 900
#define INF 0x3f3f3f3f
const ll MOD =1000000007;
typedef struct node
{
int v;
LD w;
node(int vv,LD ww):v(vv),w(ww){}
}node;
vector<node> edge[MAXN];
int n;
int vis[MAXN];
LD d[MAXN];
int r[MAXN]; //入队次数,如果一个点入队次数>=n,那么存在负环
int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
queue<int> q;
int spfa(int src)
{
while(!q.empty()) q.pop();
for(int i=0;i<=n;i++) d[i]=0,vis[i]=0,r[i]=0;
d[src]=1;
q.push(src);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=0;i<edge[u].size();i++)
{
node x=edge[u][i];
LD tmp=d[u]*x.w;
if(x.v==src&&tmp>d[src]) return 1;
if(d[x.v]<tmp)
{
d[x.v]=tmp;
if(!vis[x.v])
{
r[x.v]++;
vis[x.v]=1;
q.push(x.v);
}
}
if(r[x.v]>=n) return 1; //有环
}
}
return 0;
}
int main()
{
int m;
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;
LD w;
scanf("%d%d%Lf",&u,&v,&w);
edge[u].push_back(node(v,w));
}
//for(int i=1;i<=n;i++) r[i]=0;
int flag=0;
for(int i=1;i<=n;i++)
{
{
flag=spfa(i);
if(flag) break;
}
}
if(flag) printf("inadmissible\n");
else printf("admissible\n");
return 0;
}