2019 HDU多校训练赛第一场

2019 HDU多校训练赛第一场

欢迎参观!!==> 博客地址 <== 欢迎参观!!

大二暑假的杭电多校,作为下半年区域赛最后一搏,争取每次把题目都改完把。

第一场多校赛全员自闭,只有400左右个队伍出题,甚至2题就在首页555555。

赛前教主说了不刺激大家,特意换成了BUPT的简单场(这哪里简单了啊!!!!)

说出来你可能不信,最短路+最小割居然是签到题。当然榜有一点点歪,不过总体难度算是很难了。


1005. Path (HDU - 6582)

题意:

给你一个有向图,1到n的最短路可能有多条,需要你删去一些边使得1到n的最短路严格变长。

删掉边的费用为边的长度,求最小花费。

思路:

读懂题后,思考了一阵发现是最短路+最小割

首先将最短路的所有边存下来(最短路可能有多条),然后利用这些边建图,求新图的1到n的最小割。

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define ll long long
const ll inf=0x3f3f3f3f3f3f3f3f;
const int maxm=200500;
const int maxn=200050;
struct Edge
{
    ll next;ll to;ll w;ll fa;
}edge[maxm],edge2[maxm];
struct node
{
    int num;
    int dist;
    node(ll _num=0,ll _dist=0):num(_num),dist(_dist){}
    friend bool operator<(node a,node b)
    {
        return a.dist>b.dist;
    }
};
ll head[maxn],head2[maxn],cnt,cnt2;
ll dist[maxn],n,m,Start,End;
ll depth[maxn];
ll x[maxm],y[maxm],w[maxm];
void add(ll u,ll v,ll w)
{
    edge[cnt].next=head[u];edge[cnt].to=v;edge[cnt].w=w;head[u]=cnt++;
}
void add2(ll u,ll v,ll w)
{
    edge2[cnt2].next=head2[u];edge2[cnt2].to=v;edge2[cnt2].w=w;edge2[cnt2].fa=u;head2[u]=cnt2++;
    edge2[cnt2].next=head2[v];edge2[cnt2].to=u;edge2[cnt2].w=0;edge2[cnt2].fa=v;head2[v]=cnt2++;
}
void dij(int x)
{
    memset(dist,0x3f,sizeof(dist));
    priority_queue<node>q;q.push(node(x,0));dist[x]=0;
    while(!q.empty())
    {
        node u=q.top();q.pop();ll now=u.num;
        for(ll i=head[now];i!=-1;i=edge[i].next)
        {
            ll v=edge[i].to;
            if(dist[v]>dist[now]+edge[i].w)
            {
                dist[v]=dist[now]+edge[i].w;q.push(node(v,dist[v]));
            }
        }
    }
}
bool bfs()//分层;
{
    memset(depth,0,sizeof(depth));
    queue<int>q;
    q.push(Start);
    depth[Start]=1;
    while(!q.empty())
    {
        int temp=q.front();
        q.pop();
        for(ll i=head2[temp];i!=-1;i=edge2[i].next)
        {
            ll v=edge2[i].to;
            if(depth[v]||edge2[i].w<=0)
                continue;
            depth[v]=depth[temp]+1;
            q.push(v);
        }
    }
    return depth[End];//若为0表示没法到达也就是没有路径了;
}
int dfs(ll u,ll maxflow)
{
    if(u==End)
        return maxflow;
    int add=0;
    for(int i=head2[u];i!=-1&&add<maxflow;i=edge2[i].next)
    {
        ll v=edge2[i].to;
        if(depth[v]!=depth[u]+1)
            continue;
        if(edge2[i].w==0)
            continue;
        int tempflow=dfs(v,min(edge2[i].w,maxflow-add));
        edge2[i].w-=tempflow;
        edge2[i^1].w+=tempflow;
        add+=tempflow;
    }
    return add;
}
int dinic()
{
    ll ans=0;
    while(bfs())
    {
        ans+=dfs(Start,inf);
    }
    return ans;
}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));memset(head2,-1,sizeof(head2));cnt=cnt2=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x[i],&y[i],&w[i]);add(x[i],y[i],w[i]);
        }
        Start = 1; End = n;
        dij(Start);
        for(int i=1;i<=m;i++)
            if(dist[y[i]]==dist[x[i]]+w[i])
                add2(x[i],y[i],w[i]);
        int ans=dinic();
        printf("%d\n",ans);
    }
}

写题时一开始就想对了思路,但是网络流不会写,研究了半天,我好菜啊555.


1004. Vacation (HDU - 6581)

题意:

n + 1 n+1 n+1辆车,你在最后一辆车上,每辆车有自己的长度,速度,以及车头到重点的距离

只有一个车道,不能超车,若后车行进中碰到前车(明显后车速度大于前车)则以前车的速度贴在前后后面继续前进。

问你所在的车什么时候到达终点。

思路:

要注意,所有车到达终点之后不会消失,所以在终点后相撞的可能性是有的。

我们考虑每一辆车,到达终点的时间不会小于在他前面的车到达的时间,而后车即便相撞,也不会对当前车到达终点的时间产生影响。

所以我们枚举每一辆车为车头(车头几位后车全部连接在这辆车上),计算到达终点的时间,取最大值既为答案。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define REP(i, lim) for(int i=0;i<lim;++i)
#define REPP(i, lim) for(int i=1;i<=lim;++i)
#define FOR(i,l,r)  for(int i=l;i<r;++i)
#define clr(s) memset(s, 0, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
const int inf = 0x3f3f3f3f;
const int MAXN = 2000055;

double len[MAXN], dis[MAXN], spd[MAXN];

inline double mymax(double a, double b) {
    return (a>b) ? a:b;
}

int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//    std::ios::sync_with_stdio(false); cin.tie(0);

    int n;
    while(~scanf("%d", &n)) {
        double tot = 0;
        REP(i, n + 1) scanf("%lf", len+i);
        REP(i, n + 1) scanf("%lf", dis+i);
        REP(i, n + 1) scanf("%lf", spd+i);

        double ans = dis[0]/spd[0];

        REPP(i, n) {
            tot += len[i];
            ans = mymax(ans, (tot + dis[i]) / spd[i]);
        }

        printf("%.10lf\n", ans);
    }

    return 0;
}

ps: 这么简单的思路比赛时居然没有想到,一直在逆推逆推逆推,我没脑子,哭了。


未完待续,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值