2019杭电多校第一场

在场上只写了两题: D E

D: Vacation(模拟)

问题描述:
Tom and Jerry are going on a vacation. They are now driving on a one-way road and several cars are in front of them. To be more specific, there are n cars in front of them. The ith car has a length of li, the head of it is si from the stop-line, and its maximum velocity is vi. The car Tom and Jerry are driving is l0 in length, and s0 from the stop-line, with a maximum velocity of v0.
The traffic light has a very long cycle. You can assume that it is always green light. However, since the road is too narrow, no car can get ahead of other cars. Even if your speed can be greater than the car in front of you, you still can only drive at the same speed as the anterior car. But when not affected by the car ahead, the driver will drive at the maximum speed. You can assume that every driver here is very good at driving, so that the distance of adjacent cars can be kept to be 0.
Though Tom and Jerry know that they can pass the stop-line during green light, they still want to know the minimum time they need to pass the stop-line. We say a car passes the stop-line once the head of the car passes it.
Please notice that even after a car passes the stop-line, it still runs on the road, and cannot be overtaken.
(n <= 1e5, l,v,s <= 1e9)

题意:

一条线上n辆车,给你它们距离终点的距离,最大速度和车长,每辆车不能超车,请问最后一辆车到达终点的最短时间。

题解:

一辆速度快的车追上一辆速度慢的车相当于这两辆车合并成了一辆车。
每两辆车的合并都有一个时刻。可以用优先队列维护每相邻两辆车的合并时刻,在这个过程中维护最后一辆车行驶的路程。
车的合并可以用链表实现。合并后的车和相邻车的合并时刻也要加入优先队列维护。
取出时刻的时候判断当前车的前面那辆车是否是原来的那辆,如果不是,那么这个时刻就舍弃掉,因为前面那辆车已经和谋辆车合并了。
相当于模拟了整个过程。

ac代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 50;
struct node{
    double t;//时刻
    int id;
    int pos;
    node(){};
    node(double a, int b, int c){t = a; id = b;pos = c;}
    bool operator < (const node& x)const{return t > x.t;}
};
int pre[maxn],  nxt[maxn];
double s[maxn], v[maxn], l[maxn];
priority_queue<node> q;
int n;
int head, tail;
double cur = 0.0;//当前时间
double res = 0.0;//v0走过路程
double eps = 1e-10;
double cul(int x){
    int y = nxt[x];
    double d = s[x] - s[y] - l[y] - cur*(v[x] - v[y]);
    //cout<<"sx:"<<s[x]<<" sy:"<<s[y]<<" ly:"<<l[y]<<endl;
    return d/(v[x] - v[y]);
}//标号x的车追上前面的车需要再花费的时间
void del(int x){//合并x和它的下一辆
    int L = pre[x];
    int R = nxt[x];
    nxt[L] = R;
    pre[R] = L;
    l[R] += l[x];
    if(L == head || R == tail) return;
    if(v[R] - v[L] > -eps) return;
    q.push( node(cul(L) + cur, L, R) );
    return;
}
int main()
{
    while(scanf("%d", &n)!=EOF){
        for(int i = 0; i <= n; ++i) scanf("%lf", &l[i]); s[n+1] = 0;
        for(int i = 0; i <= n; ++i) scanf("%lf", &s[i]); v[n+1] = 1e11;
        for(int i = 0; i <= n; ++i) scanf("%lf", &v[i]); l[n+1] = 0;
        int ok = 0;
        cur = res = 0.0;
        for(int i = 1; i <= n; ++i){//有没有速度比它小的
            if(v[0] > v[i]) ok = 1;
        }
        if(!ok){
            double ans = s[0]/v[0];
            printf("%.10f\n", ans);
            continue;
        }
        while(q.size()) q.pop();
        //q.push(node(1e9, n+1,n+1));
        head = maxn-1;
        nxt[head] = 0;
        tail = n+1;
        nxt[tail] = tail;
        pre[tail] = n;

        for(int i = 0; i <= n; ++i){
            pre[i] = i-1;
            if(i == 0) pre[i] = head;
            nxt[i] = i+1;
            if(i == n) break;
            if(v[i+1] - v[i] > -eps) continue;
            q.push(node(cul(i), i, i + 1) );
        }
        double ans;
        int flag = 0;
        while(q.size()){
            node temp = q.top();q.pop();
            int id = temp.id;
            double t = temp.t;
            if(nxt[id] != temp.pos) continue;

            int id0 = nxt[head];
            double v0 = v[id0];
            //cout<<"time: "<<t<<"  road: "<<res + v0*(t-cur)<<endl;
            if(res + v0*(t-cur) >= s[0]){//下一次合并前v0就走到了终点
                ans = cur + (s[0] - res)/v0;
                printf("%.10f\n",ans);
                flag = 1;
                break;
            }

            res += v0*(t-cur);
            cur = t;
            del(id);
        }
        if(!flag) {
            double v0 = v[nxt[head]];
            ans = cur + (s[0] - res)/v0;
            printf("%.10f\n", ans);
        }
    }
}
/*
1
1 1
10 0
20 1
1
1 0
10 0
20 1
*/

E :Path(最短路 + 网络流)

问题描述:
Years later, Jerry fell in love with a girl, and he often walks for a long time to pay visits to her. But, because he spends too much time with his girlfriend, Tom feels neglected and wants to prevent him from visiting her.
After doing some research on the neighbourhood, Tom found that the neighbourhood consists of exactly n houses, and some of them are connected with directed road. To visit his girlfriend, Jerry needs to start from his house indexed 1 and go along the shortest path to hers, indexed n.
Now Tom wants to block some of the roads so that Jerry has to walk longer to reach his girl’s home, and he found that the cost of blocking a road equals to its length. Now he wants to know the minimum total cost to make Jerry walk longer.
Note, if Jerry can’t reach his girl’s house in the very beginning, the answer is obviously zero. And you don’t need to guarantee that there still exists a way from Jerry’s house to his girl’s after blocking some edges.

题意:

给一张有向图,每条边有权值,删掉一条边的代价为它的权值,求使得结点1到结点n的最短路变长的最小代价。

题解:

从结点1和结点n分别来一次单源最短路,求出每个点到1和n的最短距离dis1和disn,考虑一条边的权值为w,从u到v,如果dis1[u] + w == disn[v],说明这条边是最短路上的一条边。找出所有最短路上的边,建图求最小割即可。

#include<iostream>
#include<cstdio>
#include<string.h>
#include<queue>
#define ll long long
using namespace std;
const int maxn = 1e4 +50;
const ll inf = 0x3f3f3f3f3f3f3f3f;
struct node{
	int u,v,nxt;
	ll f;
}e[maxn*10];
int cnt = 0;
int head[maxn];
void add(int u,int v,ll f){
	e[cnt].u = u;
	e[cnt].v = v;
	e[cnt].f = f;
	e[cnt].nxt = head[u];
	head[u] = cnt++;

	e[cnt].u = v;
	e[cnt].v = u;
	e[cnt].f = 0;
	e[cnt].nxt = head[v];
	head[v] = cnt++;
}
int st,ed,ex;
int n, m;
#define P pair<ll, int>
vector<P> g1[maxn], g2[maxn];
ll dis1[maxn], disn[maxn];
priority_queue<P, vector<P>, greater<P> > Q;
void dij1(int S, ll *dis){
    for(int i = 0; i <= n; ++i) dis[i] = inf;
    dis[S] = 0;
    while(Q.size()) Q.pop();
    Q.push(P(dis[S], S));
    while(Q.size()){
        P temp = Q.top();Q.pop();
        int u = temp.second;
        if(dis[u] < temp.first) continue;
        for(int i = 0; i < g1[u].size(); ++i){
            int v = g1[u][i].second;
            ll w = g1[u][i].first;
            if(dis[u] + w < dis[v]){
                dis[v] = dis[u] + w;
                Q.push(P(dis[v], v));
            }
        }
    }
}
void dij2(int S, ll *dis){
    for(int i = 0; i <= n; ++i) dis[i] = inf;
    dis[S] = 0;
    while(Q.size()) Q.pop();
    Q.push(P(dis[S], S));
    while(Q.size()){
        P temp = Q.top();Q.pop();
        int u = temp.second;
        if(dis[u] < temp.first) continue;
        for(int i = 0; i < g2[u].size(); ++i){
            int v = g2[u][i].second;
            ll w = g2[u][i].first;
            if(dis[u] + w < dis[v]){
                dis[v] = dis[u] + w;
                Q.push(P(dis[v], v));
            }
        }
    }
}
void init(){
    scanf("%d%d", &n, &m);
	cnt = 0;
	memset(head, -1, sizeof head);
	for(int i = 1; i <= n; ++i) g1[i].clear(), g2[i].clear();
	while(m--){
        int u, v;
        ll w;
        scanf("%d%d%lld", &u, &v, &w);
        g1[u].push_back(P(w, v));
        g2[v].push_back(P(w, u));
	}
}
int dep[maxn];
int q[maxn*2];
int tot,tail;
bool bfs(){
	memset(dep,-1,(ex+1)<<2);
	dep[st] = 1;
	q[tot = 0] = st,tail = 1;
	while(tot < tail){
		int u = q[tot++];
		if(u == ed) break;
		for(int i = head[u];~i;i = e[i].nxt){
			int v = e[i].v;
			if(dep[v]!=-1 || !e[i].f) continue;
			dep[v] = dep[u] + 1;
			q[tail++] = v;
		}
	}
	return dep[ed]!=-1;
}
int cur[maxn];
ll dfs(int u,ll flow){
	ll res = flow;
	if(u == ed) return flow;
	for(int &i = cur[u];~i;i = e[i].nxt){
		int v = e[i].v;
		if(dep[v]!=dep[u] + 1 || !e[i].f) continue;
		ll d = dfs(v,min(res,e[i].f));
		e[i].f -= d;
		e[i^1].f += d;
		res -= d;
		if(res == 0) break;
	}
	if(flow == res) dep[u] = -1;//防止重新搜索
	return flow - res;
}
ll dinic(){
	ll ans = 0;
	ll d;
	while(bfs()){
		for(int i = 0;i <= ex;++i) cur[i] = head[i];
		while(d = dfs(st,inf)) ans += d;
	}
	return ans;
}
void sol(){
    dij1(1, dis1);
	dij2(n, disn);
	if(dis1[n] == inf){
        cout<<0<<endl;return;
	}
    for(int u = 1; u <= n; ++u){
        for(int i = 0; i < g1[u].size(); ++i){
            int v = g1[u][i].second;
            ll w = g1[u][i].first;
            if(dis1[u] + disn[v] + w == dis1[n]){
                add(u, v, w);
            }
        }
	}
	st = 1; ed = n; ex = n+1;
	printf("%lld\n",dinic());
}
int main(){
    int T;
    cin>>T;
	while(T--){
		init();sol();
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值