10310 Valentine's Day
该题有题解
时间限制:1000MS 内存限制:65535K
提交次数:92 通过次数:27
题型: 编程题 语言: 无限制
Description
February 14th every year is the Western Valentine's Day. Valentine's Day is called “qingrenjie” in China, on this day
lovers give each other chocolates, cards and roses to express their love or friendship.
Qiu is a boy from Jiangmen, on February 14th he is going to visit a friend Jun, Jun is a girl who loves roses very much.
In order to keep up with trends, Qiu want to give Jun a branch of flower as gift. For this special day and special meaning,
the number of roses of any branch should be an integer which consist of several 9s, such as 9, 99, 999… (at most nine 9s).
After Qiu's research, there are many ways from his home to Jun's home, but there is a limit in every road, that is to say
if you take too many roses (more than the limit), you can't go through this load. Furthermore, roses are very expensive (9.9$ each (>_<)),
so Qiu did not want to throw any roses away.
In order to please Jun, Qiu ask you a clever acmer to help him, calculate that how many roses he can send most from his house
to Jun's house through these roads?
输入格式
The first line is a number T, then T-case below.
In every case there are two number N,M in the first line.(2 <= N <= 1000, 1 <= M <= 50000) express there has N point
in the map,(Qiu is always No.1,Jun is always No.N), and there are M undirected roads in the map.
After that, there are M lines, each line there are 3 numbers (u,v,w),express that there is an undirected road
between u and v, and the road's limit is w.(it means if you have x roses, then (x <= w) you can go through this road).
输出格式
Output how many roses Qiu can send most to Jun.
输入样例
2
3 2
1 2 999
2 3 99
3 3
1 2 999
2 3 99
3 1 9999
输出样例
99
9999
提示
1.Be in sure that there have a way from 1 to N.
2.Have great data entry questions, please use scanf to read data.
3.There is only one road between u and v.
作者
admin
题意:
一幅无向图。经过每条路所能携带的玫瑰必须不大于该路的限制。求从顶点1出发,到达顶点n,所能携带的最多的玫瑰的数量。(数量必须是由若干个9组成的)【以下简称数量】
解法:
一开始直接用bfs做的。从顶点1出发,遍历边,每访问一条边,就更新从顶点1到该点的数量。
更新的具体方法如下:某时刻,从顶点cur出发,通过一条限制为w的边访问到顶点v,则有limit[v] = max( limit[v], min(limit[cur], w)
样例可以过(神奇的样例orz),但存在一个问题。
如通过A-B这条边,我们更新B。
注意到是无向边,我们还可以也应该通过该边来更新A。
但叼炸天的数据让我超时了(当然很可能是我写歪了orz)。
而,如果将之当成单向,虽然不超时,但是某些数据就足以卡到wa。
然后,又尝试了用矩阵来改写邻接表,,,发现wa的数据变少了(不要问我怎么知道测试数据。。。),但还是过不了
最后,胡乱搜索了一下,看到了生成树,顿时秒懂。
【【【嫌太长的可以直接从这里看】】】
先求一遍最大生成树,尽量用限制大的边使图连通。再在此生成树的基础上求从顶点1到顶点n的唯一路径上 限制最小的边, 再结合答案要由9组成, 即可得出答案。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1111, maxm = 55555 * 2;
struct Edge {
int v, w;
int next;
bool vis;
Edge(int _v, int _w, int _next, bool _vis):v(_v), w(_w), next(_next), vis(_vis) {}
Edge(int _v, int _w, int _next):v(_v), w(_w), next(_next), vis(0) {}
Edge() {}
};
Edge e[maxm];
int ecnt;
int head[maxn];
int n, m;
void addE(int u, int v, int w) {
e[ecnt] = Edge(v, w, head[u]);
head[u] = ecnt++;
}
void add(int u, int v, int w) {
addE(u, v, w);
addE(v, u, w);
}
int queue[maxm];
int limit[maxn];
const int INF = 0x7fffffff;
int ans[10];
void init() {
ans[0] = 9;
for(int i = 1; i < 10; i++)
ans[i] = ans[i - 1] * 10 + 9;
}
int bfs(int u) {
memset(limit, 0, sizeof(limit));
limit[u] = INF;
int front, rear;
front = rear = 0;
queue[rear++] = u;
while(front < rear) {
int cur = queue[front++];
for(int i = head[cur]; i != -1; i = e[i].next)if(!e[i].vis) {
e[i].vis = 1;
e[i ^ 1].vis = 1;
int v = e[i].v;
int w = e[i].w;
int tmp = min(limit[cur], w);
limit[v] = max(limit[v], tmp);
queue[rear++] = v;
}
}
for(int i = 9; i >=0; i--)
if(ans[i] <= limit[n])
return ans[i];
return 0;
}
int father[maxn];
int getFather(int x) {
return father[x] == -1 ? x : father[x] = getFather(father[x]);
}
bool union_(int u, int v) {
int f1 = getFather(u);
int f2 = getFather(v);
if(f1 == f2)
return false;
father[f1] = f2;
return true;
}
struct edge {
int u, v, w;
bool selected;
edge(int _u, int _v, int _w): u(_u), v(_v), w(_w), selected(0) {}
edge() {}
};
edge save[maxm];
bool cmp(const edge a, const edge b) {
return a.w > b.w;
}
void mst() {
sort(save, save + m, cmp);
memset(father, -1, sizeof(father));
int ok = n - 1;
for(int i = 0; i < m; i++) {
if(union_(save[i].u, save[i].v)) {
save[i].selected = true;
ok--;
}
if(!ok)
break;
}
}
void build(){
for(int i = 0; i < m; i++) if(save[i].selected){
add(save[i].u, save[i].v, save[i].w);
}
}
int main(void) {
init();
int t;
scanf("%d", &t);
while(t--) {
memset(head, -1, sizeof(head));
ecnt = 0;
scanf("%d%d", &n, &m);
int u, v, w;
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &w);
save[i] = edge(u, v, w);
}
mst();
build();
printf("%d\n",bfs(1));
}
return 0;
}