P1376 魔域之战
时间: 1000ms / 空间: 131072KiB / Java类名: Main
描述
小A成功地在紧要关头逃离了神奇山洞,同时他也感觉自己rp大增。现在他站在了一座阴森森的城堡前,这就是江湖人称“死亡城堡”的魔域。为了rp,小A毅然决然地走了进去……
不愧是死亡城堡,险境丛生,小A又是一个大意的人,XXX他掉进了一个陷阱。
这是一个n*n的矩阵陷阱,矩阵的每一个小格内都有一个魔鬼,并且这些魔鬼属于不同的种类,种类数不超过p(1<=p<=n*n,有可能存在某一种魔鬼不在矩阵中出现)。每一种魔鬼i都有一种战斗力c[i],不同的魔鬼战斗力不同。打魔鬼也不是那么好玩的,需要消耗小A相应数量的战斗力。当小A打败了一个魔鬼后,此种类型的魔鬼就会全部消失,这样小A就可以自由的在这种类型的格子间传送,不会消耗任何的战斗力。每到一个格子,小A可以向紧邻的上下左右四个格子进发去打魔鬼,直到走出矩阵。小A开始郁闷了,他怎样才能从矩阵的第一行出发,顺利的走到矩阵的最后一行呢?所谓的顺利,就是使自己的战斗力大于0。
现在小A求助于聪明的你,希望你能求出小A顺利走出陷阱时剩余的最大战斗力。
不愧是死亡城堡,险境丛生,小A又是一个大意的人,XXX他掉进了一个陷阱。
这是一个n*n的矩阵陷阱,矩阵的每一个小格内都有一个魔鬼,并且这些魔鬼属于不同的种类,种类数不超过p(1<=p<=n*n,有可能存在某一种魔鬼不在矩阵中出现)。每一种魔鬼i都有一种战斗力c[i],不同的魔鬼战斗力不同。打魔鬼也不是那么好玩的,需要消耗小A相应数量的战斗力。当小A打败了一个魔鬼后,此种类型的魔鬼就会全部消失,这样小A就可以自由的在这种类型的格子间传送,不会消耗任何的战斗力。每到一个格子,小A可以向紧邻的上下左右四个格子进发去打魔鬼,直到走出矩阵。小A开始郁闷了,他怎样才能从矩阵的第一行出发,顺利的走到矩阵的最后一行呢?所谓的顺利,就是使自己的战斗力大于0。
现在小A求助于聪明的你,希望你能求出小A顺利走出陷阱时剩余的最大战斗力。
输入格式
第一行:两个整数n,p;
第2到n+1行是一个n*n的矩阵,矩阵中不同的数字代表不同的格子类型;
第n+2行是p个数,代表p种魔鬼的战斗力;
最后一行:小A的初始战斗力值W。
第2到n+1行是一个n*n的矩阵,矩阵中不同的数字代表不同的格子类型;
第n+2行是p个数,代表p种魔鬼的战斗力;
最后一行:小A的初始战斗力值W。
输出格式
一个整数表示小A顺利走出陷阱时剩余的最大战斗力,如果小A走不出陷阱就输出'Dangerous!';
测试样例1
输入
样例一:
3 3
1 2 1
2 1 2
1 1 1
1 2 5
7
样例二:
3 3
1 2 1
2 1 2
3 3 3
1 2 5
2
输出
样例一:
6
样例二:
Dangerous!
备注
对于30%的数据:1<=n<=50
对于100%的数据:1<=n<=500;w<=maxlongint
对于100%的数据:1<=n<=500;w<=maxlongint
BFS的思路,就是上下左右搜索,以点权为代价,搜到一个新的类型,就把相同元素全部入队,同时记录当前剩余体力,如果走到最后一行输出即可
而图论的思路,我想的略麻烦:建立一个原点,向第一排各点连边,边权为代价;每个点向右向下连双向边;相同类型的点连边权为0的双向边,跑堆优dij
这样子边太多了,大数据会爆空间。实际上更好的方法是把同一类型的点当做一个点,每次读入数据记录不同类型点之间的关系,原点连第一排有的点的种类,最后一排出现的种类连向终点,跑SPFA即可
我只写了麻烦版本的代码,然而竟然能过···顺带吐槽下我们信手改题的07级学长,泥萌现在大概大学毕业两年了吧···
//trap
//copyright by ametake
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=250000+10;
const int maxm=6001000+10;
const int oo=2147483647;
struct data
{
int v,w,next;
}e[maxm];//edge 终点,边权,下一条同源边
struct w
{
int dist,num,k;
bool operator < (w n2)const
{
return dist>n2.dist;
}
}node[maxn];//每个node是一个点,有编号和dist
vector vec[maxn];
int ne,m,p;//矩阵大小m*m 边数带计算
int head[maxn],cost[maxn],cnt[maxn];
bool vis[maxn];
int tot,ans;
void insert(int x,int y,int w)
{
ne++;
e[ne].v=y;
e[ne].w=w;
e[ne].next=head[x];
head[x]=ne;
}
void init()
{
scanf("%d%d",&m,&p);//读入矩阵长度,鬼种类
memset(head,-1,sizeof(head));
int x;
for (int i=1;i<=m;i++)
{
for (int j=1;j<=m;j++)
{
scanf("%d",&x);
node[(i-1)*m+j].k=x;
cnt[x]++;
vec[x].push_back((i-1)*m+j);
}
}
for (int i=1;i<=p;i++) scanf("%d",&cost[i]);
scanf("%d",&tot);
return;
}
void makeit()
{
for (int i=1;i<=m;i++) insert(0,i,cost[node[i].k]);
for (int i=1;i<=p;i++)
{
if (cnt[i]>0)
{
for (int j=0;j q;
node[k].dist=0;
q.push(node[k]);
int disj,minj;//dis of j and number of j
while (!q.empty())
{
minj=q.top().num;
disj=q.top().dist;
vis[minj]=true;
q.pop();
int pi=head[minj];
while (pi!=-1)
{
if (!(vis[e[pi].v]) && (disj+e[pi].w < node[e[pi].v].dist || disj == oo))
{node[e[pi].v].dist=disj+e[pi].w;q.push(node[e[pi].v]);}
pi=e[pi].next;
}
}
//首先循环一边找出dist最小的点
//然后循环一边对于每个点以dist为中间点更小就更新dist
//从当前dist连着的边里找
}
int main()
{
//freopen("1.txt","r",stdin);
//freopen("2.txt","w",stdout);
freopen("trap.in","r",stdin);
freopen("trap.out","w",stdout);
init();
makeit();
for (int i=1;i<=m*m;i++)
{
node[i].num=i;
node[i].dist=oo;
}
node[0].num=0;
dij(0);
ans=oo;
for (int i=m*m-m+1;i<=m*m;i++) if (node[i].dist=ans) printf("%d\n",tot-ans);
else printf("Dangerous!\n");
return 0;
}
/*
for (int i=1;i<=ne;i++) printf("%d %d %d\n",i,e[i].v,e[i].w);
for (int i=1;i<=m;i++)
{
for (int j=1;j<=m;j++)
{
printf("%d ",node[(i-1)*m+j].k);
}
printf("\n");
}
for (int i=1;i<=m*m;i++) printf("%d %d\n",i,node[i].dist);
*/
/*
void makeit()
{
for (int i=1;i<=m;i++) insert(0,i,cost[node[i].k]*cnt[node[i].k]);
for (int i=1;i<=p;i++)
{
if (cnt[i]>0)
{
for (int j=0;j
——忽然一夜清香发,散作乾坤万里春

425

被折叠的 条评论
为什么被折叠?



