csu8月月赛,csuoj1978

来源:互联网 发布:mac 系统重装 编辑:程序博客网 时间:2024/04/30 12:30

此题一开始WA了很久,之前NOIP2015的时候DAY1T2也是类似的题目,然而那是无向图找最小环,于是可以到过的点不经过,这里是有向图找乘积最小环,所以到过的点还是要经过,但每条边走一次就行了,还有一个要注意的地方是,如果即将到达的位置也在队列里,首先是对这个环进行记录,然而还必须继续到这个点,因为可能存在联环和环套环的情况,所以一次要把所有可能形成的环找干净,

然而其实如果一个点在队列里面多次,那个只要找到最新的一个位置就行了。比如一个点到了3次,如果第2次到第1次这个环都没有小于1,而第3次到第1次这个环小于1,那么第3次到第2次的这个环就一定是小于1的。

spfa不太会找环,floyd讲道理全是最大数据而且多组数据的话是不能过的,然而听说竟然有人用floydA了,于是我选择dfs。

#include<cstdio>#include<cstring>#define maxl 1010#define eps 1e-7int n,m;int a[maxl],in[maxl],ehead[maxl];double mul[maxl];double w[maxl][maxl];struct ed{int to,nxt;} e[maxl*maxl];bool yes;bool vis[maxl],vise[maxl*maxl];void prework(){memset(ehead,0,sizeof(ehead));memset(vis,false,sizeof(vis));memset(in,0,sizeof(in));memset(vise,false,sizeof(vise));int u,v;double l;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)w[i][j]=100;for(int i=1;i<=m;i++){scanf("%d%d%lf",&u,&v,&l);if(l<w[u][v]-eps)w[u][v]=l;e[i].to=v;e[i].nxt=ehead[u];ehead[u]=i;}}void dfs(int k,int u){int v;double d,t;vis[u]=true;for(int i=ehead[u];i>0 && !yes;i=e[i].nxt)if(!vise[i]){v=e[i].to;d=mul[k-1]*w[u][v];vise[i]=true;if(in[v]){t=d/mul[in[v]];if(t<1-eps){yes=true;return;}}a[k]=v;in[v]=k;mul[k]=d;dfs(k+1,v);a[k]=0;in[v]=0;mul[k]=0;}}void mainwork(){yes=false;mul[0]=1;for(int i=1;i<=n;i++)if(!vis[i]){a[1]=i;in[i]=1;mul[1]=1;dfs(2,i);a[1]=0;in[i]=0;mul[1]=0;}}void print(){if(yes)printf("YES\n");elseprintf("NO\n");}int main(){while(~scanf("%d%d",&n,&m)){prework();mainwork();print();}return 0;}


另外一个神犇交我的方法,由于是最小乘积很难处理。于是对每条边取log,那么乘积<1就可以转换为和<0了,spfa判负环更加方便,而且不容易错,比赛之后写这个1A了,比赛的时候写dfsWA了2次。

#include<cstdio>#include<cstring>#include<cmath>#define maxl 1010#define eps 1e-8int n,m;int a[maxl],ehead[maxl],num[maxl];double mul[maxl],dis[maxl];double w[maxl][maxl];struct ed{int to,nxt;} e[maxl*maxl];bool yes;bool vis[maxl],in[maxl];void prework(){memset(ehead,0,sizeof(ehead));memset(vis,false,sizeof(vis));int u,v;double l;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)w[i][j]=100;for(int i=1;i<=m;i++){scanf("%d%d%lf",&u,&v,&l);if(log2(l)<w[u][v]-eps)w[u][v]=log2(l);e[i].to=v;e[i].nxt=ehead[u];ehead[u]=i;}}void spfa(int s){int head=0,tail=1,u,v;for(int i=1;i<=n;i++)dis[i]=2000000000,num[i]=0;a[1]=s;in[s]=true;num[s]=1;dis[s]=0;while(head!=tail){head++;head%=maxl;u=a[head];vis[u]=true;in[u]=false;for(int i=ehead[u];i>0;i=e[i].nxt){v=e[i].to;if(dis[u]+w[u][v]<dis[v]){dis[v]=dis[u]+w[u][v];if(!in[v]){in[v]=true;num[v]++;if(num[v]>n){yes=true;return;}tail++;tail%=maxl;a[tail]=v;}}}}}void mainwork(){yes=false;for(int i=1;i<=n && !yes;i++)if(!vis[i])spfa(i);}void print(){if(yes)printf("YES\n");elseprintf("NO\n");}int main(){while(~scanf("%d%d",&n,&m)){prework();mainwork();print();}return 0;}