8月12号的最短路:POJ 1062&&HDU 1317

下面是算是难的了吧。。。(不知道还搞得掉吗!)

先上这个。。。

                                                                           昂贵的聘礼  POJ 1062

最近比较浮躁。看了好久才懂的。。。

首先题已经知道起点!限制条件:因为有等级制度的限制。可用枚举(一个一个物品列出来)

之后发现是单向图问题!

先看代码吧。

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 int max1,a[105][105],level[105],d[105],m,vis[105];
 6 int distesila()
 7 {
 8     int i,min1,j,p;
 9     for(i=1;i<=m;i++)
10         d[i]=a[0][i];
11     for(i=1;i<=m;i++)
12     {
13         min1=1000005;
14         for(j=1;j<=m;j++)
15             if(!vis[j]&&d[j]<min1)
16             {
17                 min1=d[j];
18                 p=j;
19             }
20         vis[p]=1;//并巧妙地和该算法已有的数组结合起来
21         for(j=1;j<=m;j++)
22         {
23             if(!vis[j]&&d[j]>d[p]+a[p][j])
24                 d[j]=a[p][j]+d[p];
25         }
26     }
27     return d[1];
28 }
29 int main()
30 {
31     int max1,max2,n,i,j,p,a1,a2,b2,min1level,sd;
32     max1=10000005;
33     while(scanf("%d%d",&n,&m)!=EOF)
34     {
35         for(i=0;i<=m;i++)
36             for(j=0;j<=m;j++)
37                 a[i][j]=max1;
38         for(i=0;i<=m;i++)
39             a[i][i]=0;
40         for(i=1;i<=m;i++)
41         {
42             scanf("%d%d%d",&p,&level[i],&a1);
43             while(a1--)
44             {
45                 scanf("%d%d",&a2,&b2);
46                 a[a2][i]=b2;
47             }
48             a[0][i]=p;//既然题目中没有明确的起点且值不会小于1的,就标志为0了
49         }
50         max2=100005;
51         for(i=1;i<=m;i++)
52         {
53             min1level=level[i];//假定为最小的进行枚举
54             for(j=1;j<=m;j++)
55         {
56             if(level[j]-min1level>n||level[j]<min1level)
57                 vis[j]=1;//判断并用数组进行储存该情况
58             else
59                 vis[j]=0;
60         }
61         sd=distesila();
62         max2=min(max2,sd);
63         }//此处用枚举把每种可能算出来,取最小值
64         printf("%d
",max2);
65     }
66     return 0;
67 }

 经过三天的洗礼:终于看懂了。。。(!!!)

                                                XYZZY  HDU 1317

先讲一下题意:

有n个房间,编号1~n,小明要从1走到n。

接下给出n排:

第一个数 :到达此房间可获得的能量(100~-100) 岔口数(与哪些房间相连) 编号

注意:起点与终点获得的能量为0.初始能量为100.且每个房间只能获得一次。

因为还不知道什么是正环和负环。。。(相对于最长路与最短路来说)

首先这个题目应该求最长路吧。。。(到终点能量为正啊)

那么对应的正环就出现了,(谁会想到一开始判断1到n是否有房间连接。。。)

但是出现了正环的话,表示着什么呢?

反正求最短路时,还没遇到值为负的。。。就不清楚负环的含义。。。

看了百度百科才发现出现负环表明无最短路径。。。条件是:某点进入队列超过n次!

那么对应的正环一旦出现的话,能量对应的就为很大很大了。。。之后就判断此点到终点能不能有房间联通就行了。。。此刻就需要上面没有想到的(谁会想到一开始判断1到n是否有房间连接。。。)

那么就顺便在一开始判断1到n是否有房间连接。。。

那么关键还是理解spfa算法和负环。。。

 1 #include<iostream>
 2 #include<queue>
 3 #include<string.h>
 4 #include<algorithm>
 5 #include<stdio.h>
 6 const int MAXN=110;
 7 using namespace std;
 8 int n;
 9 int weight[MAXN];
10 int power[MAXN];
11 int _count[MAXN];//记录某点的入队列次数
12 bool map[MAXN][MAXN];//区分于reach[]的用法
13 bool reach[MAXN][MAXN];//floyd判断任何两点是否可达
14 
15 
16 void Floyd()
17 {
18     for(int k=1;k<=n;k++)
19         for(int i=1;i<=n;i++)
20             for(int j=1;j<=n;j++)
21                 reach[i][j]=(reach[i][j]||(reach[i][k]&&reach[k][j]));
22 }
23 
24 bool SPFA(int now)
25 {
26     queue<int>Q;
27     Q.push(now);
28     memset(power,0,sizeof(power));
29     memset(_count,0,sizeof(_count));
30     power[1]=100;
31     while(!Q.empty())
32     {
33         int now=Q.front();
34         Q.pop();
35         _count[now]++;
36         if(_count[now]>=n)
37             return reach[now][n];//如果某个点的次数超过n次,那么说明存在正环,此时只要判断这点到n点是否可达就行了
38         for(int next=1;next<=n;next++)
39             if(map[now][next]&&power[now]+weight[next]>power[next]&&power[now]+weight[next]>0)//避免有负数
40             {
41                 Q.push(next);
42                 power[next]=power[now]+weight[next];
43             }
44     }
45     return power[n]>0;
46 }//这里少了一个判断是否入列的数组,但没关系,不过时间较长一些
47 
48 int main()
49 {
50     while(~scanf("%d",&n)&&n!=-1)
51     {
52         memset(map,false,sizeof(map));
53         memset(reach,false,sizeof(reach));
54         for(int i=1;i<=n;i++)
55         {
56             int num;
57             scanf("%d%d",&weight[i],&num);
58             while(num--)
59             {
60                 int k;
61                 scanf("%d",&k);
62                 map[i][k]=true;
63                 reach[i][k]=true;
64             }
65         }
66         Floyd();
67         if(!reach[1][n])//如果起点到终点没有房间连接
68             printf("hopeless
");
69         else
70         {
71             if(SPFA(1))
72                 printf("winnable
");
73             else
74                 printf("hopeless
");
75         }
76     }
77     return 0;
78 }
原文地址:https://www.cnblogs.com/tt123/p/3255882.html