您的位置:首页 > 其它

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

2013-08-13 19:34 239 查看
下面是算是难的了吧。。。(不知道还搞得掉吗!)

先上这个。。。

昂贵的聘礼 POJ 1062

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

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

之后发现是单向图问题!

先看代码吧。

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int max1,a[105][105],level[105],d[105],m,vis[105];
int distesila()
{
int i,min1,j,p;
for(i=1;i<=m;i++)
d[i]=a[0][i];
for(i=1;i<=m;i++)
{
min1=1000005;
for(j=1;j<=m;j++)
if(!vis[j]&&d[j]<min1)
{
min1=d[j];
p=j;
}
vis[p]=1;//并巧妙地和该算法已有的数组结合起来
for(j=1;j<=m;j++)
{
if(!vis[j]&&d[j]>d[p]+a[p][j])
d[j]=a[p][j]+d[p];
}
}
return d[1];
}
int main()
{
int max1,max2,n,i,j,p,a1,a2,b2,min1level,sd;
max1=10000005;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<=m;i++)
for(j=0;j<=m;j++)
a[i][j]=max1;
for(i=0;i<=m;i++)
a[i][i]=0;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&p,&level[i],&a1);
while(a1--)
{
scanf("%d%d",&a2,&b2);
a[a2][i]=b2;
}
a[0][i]=p;//既然题目中没有明确的起点且值不会小于1的,就标志为0了
}
max2=100005;
for(i=1;i<=m;i++)
{
min1level=level[i];//假定为最小的进行枚举
for(j=1;j<=m;j++)
{
if(level[j]-min1level>n||level[j]<min1level)
vis[j]=1;//判断并用数组进行储存该情况
else
vis[j]=0;
}
sd=distesila();
max2=min(max2,sd);
}//此处用枚举把每种可能算出来,取最小值
printf("%d\n",max2);
}
return 0;
}


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

XYZZY HDU 1317

先讲一下题意:

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

接下给出n排:

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

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

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

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

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

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

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

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

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

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

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

#include<iostream>
#include<queue>
#include<string.h>
#include<algorithm>
#include<stdio.h>
const int MAXN=110;
using namespace std;
int n;
int weight[MAXN];
int power[MAXN];
int _count[MAXN];//记录某点的入队列次数
bool map[MAXN][MAXN];//区分于reach[]的用法
bool reach[MAXN][MAXN];//floyd判断任何两点是否可达

void Floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
reach[i][j]=(reach[i][j]||(reach[i][k]&&reach[k][j]));
}

bool SPFA(int now)
{
queue<int>Q;
Q.push(now);
memset(power,0,sizeof(power));
memset(_count,0,sizeof(_count));
power[1]=100;
while(!Q.empty())
{
int now=Q.front();
Q.pop();
_count[now]++;
if(_count[now]>=n)
return reach[now]
;//如果某个点的次数超过n次,那么说明存在正环,此时只要判断这点到n点是否可达就行了
for(int next=1;next<=n;next++)
if(map[now][next]&&power[now]+weight[next]>power[next]&&power[now]+weight[next]>0)//避免有负数
{
Q.push(next);
power[next]=power[now]+weight[next];
}
}
return power
>0;
}//这里少了一个判断是否入列的数组,但没关系,不过时间较长一些

int main()
{
while(~scanf("%d",&n)&&n!=-1)
{
memset(map,false,sizeof(map));
memset(reach,false,sizeof(reach));
for(int i=1;i<=n;i++)
{
int num;
scanf("%d%d",&weight[i],&num);
while(num--)
{
int k;
scanf("%d",&k);
map[i][k]=true;
reach[i][k]=true;
}
}
Floyd();
if(!reach[1]
)//如果起点到终点没有房间连接
printf("hopeless\n");
else
{
if(SPFA(1))
printf("winnable\n");
else
printf("hopeless\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: