2019杭电多校训练(一)

比赛链接:

http://acm.hdu.edu.cn/search.php?field=problem&key=2019+Multi-University+Training+Contest+1&source=1&searchmode=source

hdu6582

题意:

删除某些边,让$1$到$n$的最短路径发生变化

删除某条边的费用是边的长度

分析:

先用迪杰斯特拉跑一遍整个图,满足$dis[a]+w=dis[b]$的边,肯定是最短路径上的边

选出这些边,找到一个最小割集,Dinic比EK快很多,虽然渐进复杂度相同,都是$O(nm^2)$

Dinic加上弧优化后速度更快

ac代码(Dinic没有弧优化):

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pa pair<ll,ll>
using namespace std;
const ll maxn=1e4+5;
const ll maxm=1e7+10;
const ll mod=1e9+7;
vector<pair<int,int>>ve[maxn];
ll dis[maxn];
int n,m,edge_num=-1,head[maxn],dep[maxn];
bool vis[maxn];
struct Edge{
    int to,nex,v;
}edge[maxn*2];//maxn=1e4
void add_edge(int a,int b,int c)//边数从0开始,每次加上反向边,这样奇偶交替加边,重边无所谓
{
    edge[++edge_num].to=b;
    edge[edge_num].nex=head[a];
    edge[edge_num].v=c;
    head[a]=edge_num;
}
bool bfs()
{
    for(int i=1;i<=n;i++)dep[i]=1e9;
    dep[1]=0;
    queue<int>que;
    que.push(1);
    while(que.size()){
        int now=que.front();
        que.pop();
        for(int i=head[now];i!=-1;i=edge[i].nex){
            int to=edge[i].to;
            int v=edge[i].v;
            if(v&&dep[to]>dep[now]+1){
                dep[to]=dep[now]+1;
                que.push(to);
            }

        }
    }
    if(dep[n]==1e9)return false;
    else return true;
}
int dfs(int x,int lowflow)
{
    if(x==n||lowflow==0)return lowflow;
    int reslow=0;
    int used=0;
    for(int i=head[x];i!=-1;i=edge[i].nex){
        int to=edge[i].to;
        if(edge[i].v&&dep[x]+1==dep[to]){
            if(reslow=dfs(to,min(lowflow,edge[i].v))){
                edge[i].v-=reslow;
                edge[i^1].v+=reslow;
                used+=reslow;
                lowflow-=reslow;
                if(lowflow<=0)break;
            }
        }
    }
    return used;
}
void Dinic()
{
    ll maxflow=0;
    int lowflow;
    while(bfs()){
        while(lowflow=dfs(1,1e9)){
                maxflow+=lowflow;
        }
    }
    printf("%lld\n",maxflow);
}
void dj()
{
    for(int i=1;i<=n;i++)dis[i]=1e18,vis[i]=false;
    dis[1]=0;
    priority_queue<pair<ll,int>>que;
    que.push(make_pair(0,1));
    while(que.size()){
        pair<ll,int>now=que.top();
        que.pop();
        if(vis[now.second])continue;
        vis[now.second]=true;
        for(int i=0;i<ve[now.second].size();i++){
            int to=ve[now.second][i].first;
            int w=ve[now.second][i].second;
            if(dis[to]>dis[now.second]+w){
                dis[to]=dis[now.second]+w;
                que.push(make_pair(-dis[to],to));
            }
        }
    }
}
int main()
{
//    freopen("D:/a.txt","w",stdout);
//    freopen("D:/2.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++){
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            ve[a].push_back(make_pair(b,c));
        }
        dj();
        if(dis[n]==1e18){
            printf("0\n");
            continue;
        }
        for(int i=1;i<=n;i++)head[i]=-1;
        edge_num=-1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<ve[i].size();j++){
                int a=i,b=ve[i][j].first,c=ve[i][j].second;
                if(dis[a]+c==dis[b])add_edge(a,b,c),add_edge(b,a,0);
            }
        }
        Dinic();
        for(int i=1;i<=n;i++)ve[i].clear();
    }
    return 0;
}

 

ac代码(Dinic弧优化):

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pa pair<ll,ll>
using namespace std;
const ll maxn=1e4+5;
const ll maxm=1e7+10;
const ll mod=1e9+7;
vector<pair<int,int>>ve[maxn];
ll dis[maxn];
int n,m,edge_num=-1,head[maxn],dep[maxn],cur[maxn];
bool vis[maxn];
struct Edge{
    int to,nex,v;
}edge[maxn*2];//maxn=1e4
void add_edge(int a,int b,int c)//边数从0开始,每次加上反向边,这样奇偶交替加边,重边无所谓
{
    edge[++edge_num].to=b;
    edge[edge_num].nex=head[a];
    edge[edge_num].v=c;
    head[a]=edge_num;
}
bool bfs()//分层
{
    for(int i=1;i<=n;i++)dep[i]=1e9;
    dep[1]=0;
    queue<int>que;
    que.push(1);
    while(que.size()){
        int now=que.front();
        que.pop();
        for(int i=head[now];i!=-1;i=edge[i].nex){
            int to=edge[i].to;
            int v=edge[i].v;
            if(v&&dep[to]>dep[now]+1){
                dep[to]=dep[now]+1;
                que.push(to);
            }

        }
    }
    if(dep[n]==1e9)return false;
    else return true;
}
int dfs(int x,int lowflow)
{
    if(x==n||lowflow==0)return lowflow;
    int reslow=0;
    int used=0;
    for(int &i=cur[x];i!=-1;i=edge[i].nex){
        int to=edge[i].to;
        if(edge[i].v&&dep[x]+1==dep[to]){
            if(reslow=dfs(to,min(lowflow,edge[i].v))){
                edge[i].v-=reslow;
                edge[i^1].v+=reslow;
                used+=reslow;
                lowflow-=reslow;
                if(lowflow<=0)break;
            }
        }
    }
    return used;
}
void Dinic()
{
    ll maxflow=0;
    int lowflow;
    while(bfs()){
        for(int i=1;i<=n;i++)cur[i]=head[i];
        while(lowflow=dfs(1,1e9)){
                maxflow+=lowflow;
        }
    }
    printf("%lld\n",maxflow);
}
void dj()
{
    for(int i=1;i<=n;i++)dis[i]=1e18,vis[i]=false;
    dis[1]=0;
    priority_queue<pair<ll,int>>que;
    que.push(make_pair(0,1));
    while(que.size()){
        pair<ll,int>now=que.top();
        que.pop();
        if(vis[now.second])continue;
        vis[now.second]=true;
        for(int i=0;i<ve[now.second].size();i++){
            int to=ve[now.second][i].first;
            int w=ve[now.second][i].second;
            if(dis[to]>dis[now.second]+w){
                dis[to]=dis[now.second]+w;
                que.push(make_pair(-dis[to],to));
            }
        }
    }
}
int main()
{
//    freopen("D:/a.txt","w",stdout);
//    freopen("D:/2.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++){
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            ve[a].push_back(make_pair(b,c));
        }
        dj();
        if(dis[n]==1e18){
            printf("0\n");
            continue;
        }
        for(int i=1;i<=n;i++)head[i]=-1;
        edge_num=-1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<ve[i].size();j++){
                int a=i,b=ve[i][j].first,c=ve[i][j].second;
                if(dis[a]+c==dis[b])add_edge(a,b,c),add_edge(b,a,0);
            }
        }
        Dinic();
        for(int i=1;i<=n;i++)ve[i].clear();
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/carcar/p/11231075.html

时间: 2024-11-09 05:46:46

2019杭电多校训练(一)的相关文章

HDU 4901(杭电多校训练#3 1005题)The Romantic Hero(DP)

题目地址:HDU 4901 这题没想到最后居然能够做出来.... 这题用了两次DP,先从前往后求一次异或的,再从后往前求一次与运算的.分别是 1:求异或的时候,定义二维数组huo[1000][1024],前者指第几位,后者是哈希的思想,若huo[x][y]=2则表示最右边的数为第x位时,异或值为y的出现了两次,需要再定义一个hash数组,来保存前面出现的所有情况,再找有多少位的时候,用hash数组中出现的所有的值与当前的第x位的数字进行异或. 2:求与的时候,定义二维数组yu[1000][102

HDU 4920(杭电多校训练#5 1010 题) Matrix multiplication(不知道该挂个什么帽子。。。)

题目地址:HDU 4920 对这个题简直无语到极点...居然O(n^3)的复杂度能过....方法有三.. 1:进行输入优化和输出优化..(前提是你的输入优化不能太搓...) 2:利用缓存优化..详情请看该论文.大体就是将后两个for循环换过来,让坐标改变的频率降下来. 3:叉姐题解中说的正规方法..利用biset存储,进行预处理..(其实我还没看懂.. 我只写了个第二种...代码如下,共勉..神奇的小代码.. #include <iostream> #include <cstdio>

HDU 4864 Task (贪心+STL多集(二分)+邻接表存储)(杭电多校训练赛第一场1004)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4864 解题报告:有n台机器用来完成m个任务,每个任务有一个难度值和一个需要完成的时间,每台机器有一个可以工作的最长时间和一个可以完成的任务的难度的最大值, 一台机器能完成一个任务的条件是这台机器的最长工作时间和能完成任务的难度值必须都大于等于这个任务,而且一台机器最多完成一个任务,假设一个任务的时间为t,难度值为x,那么完成这个任务可以赚到的钱 money = 500 * t + 2 * x; 现在

HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是把区间 (l,r) 中大于x的数跟 x 做gcd操作. 线段树区间更新的题目,每个节点保存一个最大和最小值,当该节点的最大值和最小值相等的时候表示这个区间所有的数字都是相同的,可以直接对这个区间进行1或2操作, 进行1操作时,当还没有到达要操作的区间但已经出现了节点的最大值跟最小值相等的情况时,说明

HDU 4941 Magical Forest(map映射+二分查找)杭电多校训练赛第七场1007

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4941 解题报告:给你一个n*m的矩阵,矩阵的一些方格中有水果,每个水果有一个能量值,现在有三种操作,第一种是行交换操作,就是把矩阵的两行进行交换,另一种是列交换操作,注意两种操作都要求行或列至少要有一个水果,第三种操作是查找,询问第A行B列的水果的能量值,如果查询的位置没有水果,则输出0. 因为n和m都很大,达到了2*10^9,但水果最多一共只有10^5个,我的做法是直接用结构体存了之后排序,然后m

2019杭电多校第九场

2019杭电多校第九场 熟悉的后半场挂机节奏,又苟进首页了,很快乐 1001. Rikka with Quicksort upsolved 不是我做的,1e9调和级数分段打表 1002. Rikka with Cake solved at 01:11 有一个矩形,给你很多射线(射线只有横平竖直的四个方向),问把矩形切成了多少块 队友说答案是交点数加一,作为一个合格的工具人,当然是把队友的想法实现啦 二维坐标离散化枚举纵坐标维护横坐标,常规套路,树状数组也可以做(我是线段树写习惯了根本没想起来还有

2019 杭电多校 第五场

2019 Multi-University Training Contest 5 补题链接:2019 Multi-University Training Contest 5 罚时爆炸 自闭场 1004 equation (HDU 6627) 题意: 给定一个整数 \(C\) 和 \(N\) 组 \(a_i,b_i\),求 \(∑_{i=1}^N|a_i\cdot x + b_i| = C\) 的所有解,如果有无穷多个解就输出 -1. 思路 分类讨论 分类讨论去绝对值.根据 \(b_i / a_i

2019年杭电多校训练1012

题意:给出n,c,k.接着给出n个数字(在1~c之间),问最长的区间长度.该区间满足任意一个出现的数字至少出现k次. 思路:我们可以把可能满足条件的区间进行判断,然后按区间内不符合条件的数的下标进行再次分区间,再次进行判断. 一直到所有的可能满足条件的区间都被判断完. 坑点:在分区间时,对于边界的处理比较繁琐,(l,r)与不满足条件的数的下标的关系要特别注意. #include<bits/stdc++.h> using namespace std; #define met(a,b) memse

2019杭电多校&amp;CCPC网络赛&amp;大一总结

多校结束了, 网络赛结束了.发现自己还是太菜了,多校基本就是爆零和签到徘徊,第一次打这种高强度的比赛, 全英文,知识点又很广,充分暴露了自己菜的事实,发现数学还是很重要的.还是要多刷题,少玩游戏. 网络赛也打的不好, 开场写01,先是思路错,再是没考虑特判,直接罚时爆炸,再是写06,题意又看错,看了很久.其中队友过07, 我看08,队友03,08先乱写了个优先队列直接t,然后边吃边想,想到正解,忘记加换行... 最后看02, 也没写出来,队友03也是没调出来, 口上说着主攻数据结构,连想的算法都