hdu 1317+hdu 1535(SPFA)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1317

思路:只要在SPFA中将一个条件,就不会进入负环。那么如果有正环呢,显然退出条件是某个点入队列次数>=n,此时退出时只需判断当前点是否与n存在路径,这步可以用Floyd来实现。。。

View Code
 1 #include<iostream>
 2 #include<queue>
 3 const int MAXN=110;
 4 using namespace std;
 5 int n;
 6 int weight[MAXN];
 7 int power[MAXN];
 8 int _count[MAXN];//记录某点的入队列次数
 9 bool map[MAXN][MAXN];
10 bool reach[MAXN][MAXN];//floyd判断任何两点是否可达
11 
12 
13 void Floyd(){
14     for(int k=1;k<=n;k++){
15         for(int i=1;i<=n;i++){
16             for(int j=1;j<=n;j++){
17                 reach[i][j]=(reach[i][j]
18                 ||(reach[i][k]&&reach[k][j]));
19             }
20         }
21     }
22 }
23 
24 bool SPFA(int now){
25     queue<int>Q;
26     Q.push(now);
27     memset(power,0,sizeof(power));
28     memset(_count,0,sizeof(_count));
29     power[1]=100;
30     while(!Q.empty()){
31         int now=Q.front();
32         Q.pop();
33         _count[now]++;
34         if(_count[now]>=n)return reach[now][n];//如果某个点的次数超过n次,那么说明存在正环,此时只要判断这点到n点是否可达就行了
35         for(int next=1;next<=n;next++){
36             if(map[now][next]&&power[now]+weight[next]>power[next]
37             &&power[now]+weight[next]>0){
38                 Q.push(next);
39                 power[next]=power[now]+weight[next];
40             }
41         }
42     }
43     return power[n]>0;
44 }
45 
46 int main(){
47     while(~scanf("%d",&n)&&n!=-1){
48         memset(map,false,sizeof(map));
49         memset(reach,false,sizeof(reach));
50         for(int i=1;i<=n;i++){
51             int num;
52             scanf("%d%d",&weight[i],&num);
53             for(int j=1;j<=num;j++){
54                 int k;
55                 scanf("%d",&k);
56                 map[i][k]=true;
57                 reach[i][k]=true;
58             }
59         }
60         Floyd();
61         if(!reach[1][n]){
62             printf("hopeless\n");
63         }else {
64             if(SPFA(1)){
65                 printf("winnable\n");
66             }else 
67                 printf("hopeless\n");
68         }
69     }
70     return 0;
71 }

 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1535

思路:正向建一次图,反向建一次图,然后两次SPFA就可以了,采用vector的邻接表形式,特别好用。。。

View Code
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 const int MAXN=1000000+10;
 5 typedef long long ll;
 6 const ll inf=1e60;
 7 using namespace std;
 8 struct Node{
 9     int v,w;
10 };
11 vector<Node>mp1[MAXN];//正向建图
12 vector<Node>mp2[MAXN];//反向建图
13 int n,m;
14 ll cost[MAXN];
15 
16 void SPFA(int u,vector<Node>mp[]){
17     for(int i=2;i<=n;i++)cost[i]=inf;
18     cost[1]=0;
19     queue<int>Q;
20     Q.push(u);
21     while(!Q.empty()){
22         int u=Q.front();
23         Q.pop();
24         for(int i=0;i<mp[u].size();i++){
25             int v=mp[u][i].v;
26             int w=mp[u][i].w;
27             if(cost[v]>cost[u]+w){
28                 cost[v]=cost[u]+w;
29                 Q.push(v);
30             }
31         }
32     }
33 }
34 
35 
36 int main(){
37     int _case;
38     scanf("%d",&_case);
39     while(_case--){
40         scanf("%d%d",&n,&m);
41         for(int i=1;i<=n;i++){
42             mp1[i].clear();
43             mp2[i].clear();
44         }
45         for(int i=1;i<=m;i++){
46             int u,v,w;
47             scanf("%d%d%d",&u,&v,&w);
48             Node p1,p2;
49             p1.v=u,p2.v=v,p1.w=p2.w=w;
50             mp1[u].push_back(p2);
51             mp2[v].push_back(p1);
52         }
53         SPFA(1,mp1);//正向求一次
54         ll ans=0;
55         for(int i=2;i<=n;i++){
56             ans+=cost[i];
57         }
58         SPFA(1,mp2);//反向求一次
59         for(int i=2;i<=n;i++){
60             ans+=cost[i];
61         }
62         printf("%lld\n",ans);
63     }
64     return 0;
65 }
66 
67         

 

posted @ 2013-04-13 17:43  ihge2k  阅读(946)  评论(0编辑  收藏  举报