题目链接:http://poj.org/problem?id=1062
题目为中文,打开链接阅读即可。
注意点:驸马在进行一系列交换的时候,会与多种等级的人交换,要求的是其中最大等级和最小等级的差不能大于M(或者任意两点的等级差不能大于M)。
开始使用Floyd写,但是发现等级差很难控制,做了长时间后,看了大牛的代码,发现使用Dijkstra+枚举,可以很好的控制等级差,唉,大牛就是大牛,自己还要努力!!
枚举等级差分析:
这一系列的等级如果满足某个区间[a,b],就能满足等级差要求。怎么确定这个区间呢,题意知道国王要出现在任何一条交换路径,国王的等级为rank[1],先可以想到参与交换的等级必须在区间[rank[1]-M,rang[1]+M]内,但是在这个区间内有等级差大于M的情况,但是可以将这个区间分为[rank[1]-M,rank[1]],[rank[1]-M+1,rank[1]+1],[rank[1]-M+2,rank[1]+2].......[rank[1],rank[1]+M],这些子区间涵盖了区间[rank[1]-M,rank[1]+M],而且在这些区间里面所有的等级差都不会超过M,所以只需要枚举这些区间,求出各个区间内最小cost,然后取其中最小的(mincost)即可。
代码:
#include<stdio.h>
#include<string.h>
#define INF 10000000
int map[101][101];
int rank[101],v[101];
int dis[101],inrank[101],visted[101];
int M,N;
int dijkstra()
{
int i,j;
int u,min;
memset(visted,0,sizeof(visted));
dis[1]=0;
for(i=2;i<=N;i++)
dis[i]=INF;
for(i=1;i<=N;i++)
{
min=INF;
for(j=1;j<=N;j++)
if(min>dis[j] && inrank[j] && !visted[j])
{
min=dis[j];
u=j;
}
visted[u]=1;
for(j=1;j<=N;j++)
if(dis[j]>dis[u]+map[u][j] && inrank[j])
dis[j]=dis[u]+map[u][j];
}
min=INF;
for(i=1;i<=N;i++)
if(min>dis[i]+v[i])
min=dis[i]+v[i];
return min;
}
void main()
{
int i,j;
int n,renum,reprice;
int cost,mincost=INF;
scanf("%d%d",&M,&N);
for(i=0;i<=N;i++)
for(j=0;j<=N;j++)
if(i==j)
map[i][j]=0;
else
map[i][j]=INF;
for(i=1;i<=N;i++)
{
scanf("%d%d%d",&v[i],&rank[i],&n);
for(j=1;j<=n;j++)
{
scanf("%d%d",&renum,&reprice);
map[i][renum]=reprice;
}
}
for(i=0;i<=M;i++)
{
memset(inrank,0,sizeof(inrank));
for(j=1;j<=N;j++)
{
if(rank[j]>=rank[1]-M+i && rank[j]<=rank[1]+i)
inrank[j]=1;
}
cost=dijkstra();
if(mincost>cost)
mincost=cost;
}
printf("%d\n",mincost);
}