ssoj2472遇险

【题目】

Bender所在的区域,可以看作一个n个点(街角)m条边()的无向图,每条边有一个运动难度,通过这条边所消耗的时间等于其运动难度除以Bender的行动能力。而每到一个新的街角,由于示威者们都拿着区域性酒精转转化器,Bender的酒精含量会降低,造成Bender的行动能力都会变成原来的十分之一。 

Bender终于回到了基地,他将经历告诉了FryFry问他怎样选择的道路。Bender当然是选择时间最少的,而且使自己尽量清醒的。

【题解】可以将经过的每条边的时间看作总时间上的一位数。最少时间必定是最少位数上的最小数。从终点可能能够连边到其他点,代价为零,将这些点也记为终点,记录他们到终点的层数。从起点开始枚最小层数,从这一层一层层推回去,每次都取最小的边权,并将满足的点入列。

【代码】

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=100005;
struct data{
    int v,nxt,w;
}e[maxn<<1];
int n,m,fst[maxn],ans[maxn],tot=0;
int pas[maxn],cen[maxn],d[maxn],cnt=0;
bool vst[maxn],inz[maxn],inq[maxn];
inline int get(){
    char c;while(!isdigit(c=getchar()));
    int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
    return v;
}
inline void add(int x,int y,int z){
    e[++cnt].v=y;e[cnt].w=z;e[cnt].nxt=fst[x];fst[x]=cnt;
}
inline void bfs_find_w_zero(){
    queue<int>q;
    memset(inz,0,sizeof(inz));
    inz[n]=1;pas[n]=0;q.push(n);
    while(!q.empty()){
	    int x=q.front();q.pop();
	    for(int i=fst[x];i;i=e[i].nxt){
		    int y=e[i].v;
		    if(!inz[y] && !e[i].w)inz[y]=1,pas[y]=pas[x]+1,q.push(y);
		}
	}
	//for(int i=1;i<=n;++i)if(inz[i])printf("%d   \n",i);
}
inline void bfs_get_cen(){
    queue<int>q;
    memset(vst,0,sizeof(vst));
    memset(cen,0x3f,sizeof(cen));
    q.push(1);vst[1]=1;cen[1]=1;
    while(!q.empty()){
	    int x=q.front();q.pop();
	    for(int i=fst[x];i;i=e[i].nxt){
		    int y=e[i].v;
		    if(cen[y]>cen[x]+1){
			    cen[y]=cen[x]+1;
			    if(!vst[y])vst[y]=1,q.push(y);
			}
		}
	}
//-	for(int i=1;i<=n;++i)printf("%d  %d\n",i,cen[i]);
}
inline void bfs_get_ans(){
	int t=maxn;int l=1,r=0,p[maxn];
	memset(inq,0,sizeof(inq));
	memset(d,0,sizeof(d));
    for(int i=1;i<=n;++i)if(inz[i])t=min(t,cen[i]);
    for(int i=1;i<=n;++i)if(cen[i]==t && inz[i])p[++r]=i,inq[i]=1,d[i]=pas[i];
    if(inq[1]){
	    printf("0\n%d\n",d[1]+1);
	    return;
	}
	while(l<=r){
		int rr=r;t=maxn;
	    for(int i=l;i<=rr;++i){
			int x=p[i];
		//	printf("       %d\n",x);
	        for(int j=fst[x];j;j=e[j].nxt){
				int y=e[j].v;
		        if(cen[y]+1==cen[x] && !inz[y])t=min(t,e[j].w);
		    }
		}
		if(t==maxn)break;
		ans[++tot]=t;
		for(int i=l;i<=rr;++i){
			int x=p[i];
		    for(int j=fst[x];j;j=e[j].nxt){
			    int y=e[j].v;
			    if(cen[y]+1==cen[x] && e[j].w==t){
				    if(!inq[y])d[y]=d[x],p[++r]=y,inq[y]=1;
				    else if(d[y]>d[x])d[y]=d[x];
				}
			}
		}
		l=rr+1;
	}
	for(int i=1;i<=tot;++i)printf("%d",ans[i]);
	printf("\n%d\n",tot+d[1]+1);
}
int main(){
    n=get();m=get();
    for(int i=1;i<=m;++i){
	    int x=get()+1,y=get()+1,z=get();
	    add(x,y,z);add(y,x,z);
	}
	bfs_find_w_zero();
	bfs_get_cen();
	bfs_get_ans();
	return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值