UVA 10537 Toll! Revisited (逆推,最短路)

从终点逆推,d[u]表示进入u以后剩下的货物,那么进入u之前的货物数量设为y,d[u] = x,那么y-x=ceil(y/20.0)=(y-1)/20+1=(y+19)/20。

(y-x)*20+r=y+19,0≤r≤19,即19*y=20*x+r,根据题意y应该尽量小,x的部分是不能变动的,所以y=x+ceil(x/19.0)。

然后从起点找一条字典序最小的路径即可,因为每个字母都是独一无二的,所以不必bfs,每次记录一个点就够了。

 

#include<bits/stdc++.h>
using namespace std;

const int maxn = 54, maxm = maxn*maxn, town = 0, village = 1;
bool g[maxn][maxn];
int head[maxn],nxt[maxm],to[maxm],ecnt;
int tp[maxn];
int id[256];
char rid[256];

void addEdge(int u,int v)
{
    to[ecnt] = v;
    nxt[ecnt] = head[u];
    head[u] = ecnt++;
}
int id_cnt;

void init()
{
    memset(head,-1,sizeof(head));
    memset(id,-1,sizeof(id));
    memset(g,0,sizeof(g));
    ecnt = 0;
    id_cnt = 0;
}

inline int ID(char c) {
    if(~id[c]) return id[c];
    id[c]= id_cnt;
    rid[id_cnt] = c;
    tp[id_cnt] = 'a'<=c&&c<='z';//写成isalpha(c)-1;WA了
    return id_cnt++;
}
typedef long long ll;
typedef pair<ll,int> Node;
#define fi first
#define se second

ll d[maxn];
void dijkstra(int s,ll p)
{
    memset(d,0x7f,sizeof(d));
    priority_queue<Node,vector<Node>,greater<Node> > q;
    q.push(Node(d[s] = p,s));
    while(q.size()){
        Node x = q.top(); q.pop();
        int u = x.se;
        if(d[u] != x.fi) continue;
        ll t = (tp[u]?(1+d[u]):((d[u]+18)/19+d[u]));
        for(int i = head[u]; ~i; i = nxt[i]){
            int v = to[i];
            if(d[v] > t ){
                q.push(Node(d[v]= t,v));
            }
        }
    }
}

ll cost(int u,int v)
{
    return tp[v]?1:((d[u]+19)/20);
}

void FindPath(int s,int e)
{
    int u = s;
    while(u != e){
        printf("%c-",rid[u]);
        int nex = -1;
        for(int i = head[u]; ~i; i = nxt[i]){
            int v = to[i];
            if(d[u]- cost(u,v) >= d[v]){
                if(~nex) {
                    if(rid[v] < rid[nex]) nex = v;
                }else nex = v;
            }
        }
        swap(nex,u);
    }
    printf("%c\n",rid[e]);
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n;
    char a[10],b[10];
    int kas = 0;
    while(scanf("%d",&n),~n){
        init();
        while(n--){
            scanf("%s%s",a,b);
            int u = ID(*a), v = ID(*b);
            if(!g[u][v]){
                g[u][v] = g[v][u] = true;
                addEdge(u,v); addEdge(v,u);
            }
        }
        ll p;
        scanf("%lld%s%s",&p,a,b);
        int s = ID(*a),e = ID(*b);
        dijkstra(e,p);
        printf("Case %d:\n%lld\n",++kas,d[s]);
        FindPath(s,e);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/jerryRey/p/4780777.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值