UVA1027 Toll
Description
给定一张无向图,每个节点用
A\(\sim\)Z或a\(\sim\)z表示,所有大写字母均为城镇,所有小写字母均为村庄。经过每个城镇或村庄均要收税,进入那个点便收税,出来不用收税(所以起点是不用收费的)。
城镇是每运送 \(20\) 件货物便收 \(1\) 件货物的税(最后若不足 \(20\) 件的话按 \(20\) 件算)。
村庄是无论多少货物,只需要收 \(1\) 件货物的税即可。
你现在要运送一些货物从 \(S\) 到 \(T\),要求到达 \(T\) 时需要至少剩下 \(p\) 件货物。
问从 \(S\) 出发时最少携带多少货物才能满足要求,有多组测试数据。
Solution
对于字符的点我们很难处理,所以一开始要把所有字符转为数字,文中使用的方法是直接 ASCII 码转换。
发现起点的答案未知,但是终点答案已知,所以可以通过终点反推起点,考虑从终点开始,向起点计算。
初值为 \(dis[T] = p\),类似与求最短路(dijkstra)的算法,把城镇和村庄分开处理
-
如果是村庄,那直接把边权视作 \(1\),更新即可。
-
如果是城镇,考虑二分答案,二分从上一个点最少要带多少货物过来即可。
答案即为 \(dis[S]\)。
注意,这题虽然点个数不多,但不能使用floyd算法做,因为floyd是基于dp的松弛做法,但是这题的边权并不是固定的,会变化,所以会错。
Code
注意题中输出格式的特殊要求。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#define rep(_, __, ___) for(int _ = __; _ <= ___; _++)
#define per(_, __, ___) for(int _ = __; _ >= ___; _--)
using namespace std;
const int N = 205;
int n;
vector <int> g[N];
int dis[N], b[N], T;
int tar;
char ch1, ch2;
int s, t;
priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > que;
bool ok(int midd, int xx)
{
int res;
if(midd % 20 == 0)
{
res = midd / 20;
}
else
{
res = midd / 20 + 1;
}
return (midd - res) >= xx;
}
void dijkstra()
{
dis[t] = tar;
que.push(make_pair(tar, t));
while(!que.empty())
{
int k = que.top().second;
que.pop();
if(b[k]) continue;
b[k] = 1;
for(int i = 0; i < g[k].size(); i++)
{
int v = g[k][i];
if(b[v]) continue;
if('A' <= char(k + 'A' - 1) && char(k + 'A' - 1) <= 'Z')//如果该点是城镇,则就按城镇的方法更新接下来的点
{
int temp;
int low = dis[k], high = 1000000;//这里high的取值还能再小一点
while(low <= high)//二分
{
int mid = (low + high) / 2;
if(ok(mid, dis[k]))
{
high = mid - 1;
temp = mid;
}
else
{
low = mid + 1;
}
}
if(dis[v] > temp)
{
dis[v] = temp;
que.push(make_pair(dis[v], v));
}
}
else//如果是村庄,就按边权为1的最短路做
{
if(dis[v] > dis[k] + 1)
{
dis[v] = dis[k] + 1;
que.push(make_pair(dis[v], v));
}
}
}
}
}
int main()
{
// freopen("toll.in", "r", stdin);
// freopen("toll.out", "w", stdout);
scanf("%d", &n);
while(n != -1)
{
T++;
memset(dis, 0x3f, sizeof dis);
memset(b, 0, sizeof b);
rep(i, 1, 150)//多测要清空
{
g[i].clear();
}
for(int i = 1; i <= n; i++)
{
cin >> ch1 >> ch2;
g[ch1 - 'A' + 1].push_back(ch2 - 'A' + 1);
g[ch2 - 'A' + 1].push_back(ch1 - 'A' + 1);
}
cin >> tar >> ch1 >> ch2;
s = ch1 - 'A' + 1;
t = ch2 - 'A' + 1;
dijkstra();
printf("Case %d: %d\n", T, dis[s]);
scanf("%d", &n);
}
return 0;
}

浙公网安备 33010602011771号