这题算是我自己做的了,从开始建模构图构思,敲代码,调试,重新想思路。虽然做这题做了很久,但是也算是了结了我的一个心愿吧,昂贵的聘礼是我从ACM入门时就开始想做掉的题目了,这次下了决心终于做掉了,开心啊~
---------------------------------------------------分割线-----------------------------------------------------------
这题可以用最短路径的方法来做,A,B物品能够换则有一条带权边。边的值为A换B的价格,这题是有向边,所以付边值时不能两边同时改值。另外这题的关键之处在于构图与等级限制。开始我写的是酋长以下到M的等级范围,WA了,这也就是我不懂为啥要枚举等级的原因了。因为酋长的等级不一定是最高的,所以规定一个范围,在此范围中的等级间可以进行交易,交易的结果就是对图进行修改。这里用了保留整个图的思想,就是只改变[0][i]的值而整个图并没有什么变化。下次运算也同样进行即可。原物品有一个价值,于是我便把该点的价值联系到[i][120]的边权值,这样便能够形成一个符合题意的图了。
另外要注意的是最大最小值的赋值,这里又WA了一次,最小值一定要取得比题中数据大,防止发生悲剧。
#include<iostream>
#include<cmath>
#define MAXN 121
#define INF (1<<30)
using namespace std;
int dij[MAXN][MAXN];
int level[MAXN];
int N,M;
void dijstra( int up,int down )
{
int i,j,k;
bool visited[MAXN];
memset( visited,0,sizeof(visited) );
dij[1][0]=dij[0][1]=0;
visited[0]=true;
for( i=2;i<MAXN;i++ )
dij[0][i]=dij[i][0]=INF;
k=0;
for( i=1;i<=N;i++ )
{
int min=INF;
for( j=1;j<=N;j++ )
if( !visited[j] && min>dij[0][j] )
{
min=dij[0][j];k=j;
}
visited[k]=true;
for( j=1;j<=N;j++ )
if( dij[0][j]>dij[0][k]+dij[k][j] && ( level[j]<=up&&level[j]>=down ) )
dij[0][j]=dij[0][k]+dij[k][j];
}
}
int main()
{
int i,j;
while( scanf( "%d %d",&M,&N )!=EOF )
{
memset( dij,0x7F,sizeof(dij) );
memset( level,0,sizeof(level) );
level[120]=100;
int maxLevel=0;
int minLevel=INF;
int min=INF;
for( i=1;i<=N;i++ )
{
int a,b,c;
scanf( "%d %d %d",&a,&b,&c );
dij[i][120]=a;
level[i]=b;
maxLevel=maxLevel>b?maxLevel:b;
minLevel=minLevel>b?b:minLevel;
for( j=1;j<=c;j++ )
{
scanf( "%d%d",&a,&b );
dij[i][a]=b;
}
}
while( maxLevel>=0 )
{
if( ( level[1]<=maxLevel&&level[1]>=maxLevel-M ) )
dijstra( maxLevel,maxLevel-M );
maxLevel--;
dij[0][1]=dij[1][0]=0;
for( i=1;i<=N;i++ )
if( min>dij[0][i]+dij[i][120] )
min=dij[0][i]+dij[i][120];
}
printf( "%d\n",min );
}
return 0;
}