scau_oj 10310 Valentine's Day (最大生成树、bfs)

5 篇文章 0 订阅
2 篇文章 0 订阅

 

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;
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值