这题调了有24小时。。。重写了N遍。。。最后被别人发现是数组开小了。。。= =。。。算了,,全当练习手速了。。。
思路:利用SPFA判断是否存在负圈
题目描述与实际数据不大相符,按照题目描述应当是从任意点出发的连通分支是否存在负圈,而实际上只要判断从第一个点出发是否构成负圈就足够了。。可能是数据强度不够。。
#include <stdio.h> #include <string.h> #define MAXN 1025 #define inf 100000000 int head[MAXN],next[MAXN*MAXN],pnt[MAXN*MAXN],length[MAXN*MAXN]; int tot; int dist[MAXN]; int queue[1000000]; int qhead,qtail; int inqueue[MAXN]; int countq[MAXN]; int n,m,w; int a,b,len; void addedge(int a,int b,int len) { pnt[tot]=b; length[tot]=len; next[tot]=head[a]; head[a]=tot++; } int spfa(int src) { qhead=0; qtail=1; for (int i=0; i<n; i++) { dist[i]=inf; } memset(countq,0,sizeof(countq)); memset(inqueue,0,sizeof(inqueue)); dist[src]=0; queue[qhead]=src; inqueue[queue[qhead]]=1; countq[queue[qhead]]++; while (qhead<qtail) { int idx=head[queue[qhead]]; while (~idx) { if (dist[pnt[idx]] > dist[queue[qhead]]+length[idx]) { dist[pnt[idx]] = dist[queue[qhead]]+length[idx]; if(!inqueue[pnt[idx]]) { inqueue[pnt[idx]]=1; countq[pnt[idx]]++; if(countq[pnt[idx]]>n+1) return 1; queue[qtail++]=pnt[idx]; } } idx=next[idx]; } inqueue[queue[qhead]]=0; qhead++; } return 0; } int main() { int ncase; scanf("%d",&ncase); while (ncase--) { tot=0; memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); scanf("%d%d%d",&n,&m,&w); for(int i=0; i<m; i++) { scanf("%d%d%d",&a,&b,&len); addedge(a-1,b-1,len); addedge(b-1,a-1,len); } for(int i=0; i<w; i++) { scanf("%d%d%d",&a,&b,&len); addedge(a-1,b-1,-len); } //for(int i=0; i<n; i++) { // addedge(n,i,0); //} //for (int i=0; i<=n; i++) { // int idx=head[i]; // while (~idx) { // printf("%d->%d:%d\n",i,pnt[idx],length[idx]); // idx=next[idx]; // } //} int ans=0; if(spfa(0)) ans=1; if(ans) printf("YES\n"); else printf("NO\n"); //for (int i=0; i<=n; i++) { // printf("%d %d\n",i,dist[i]); //} } }
PS,如果按照之前的题意理解来做的话,可以建超级源点、