zoukankan      html  css  js  c++  java
  • CF1558E Down Below

    一、题目

    点此看题

    二、解法

    果然是 ( t tourist) 搞的神题,很有启发意义。

    首先这种经过每个点只有一次贡献的题,要么贪心要么网络流,(dp) 是难以解决的。

    可以用类似增广的思路,也就是我们维护一个连通块,每次向连通块内加入一条从连通块出发,再回到连通块的增广路径,如果最后所有点都在连通块内那么就完成了增广。

    但是这样做有后效性吗?考虑不能移动到上一个点的限制,由于增广之后上一个点是原先不在连通块内部的点,所以下一次增广一定可以从任意节点出发,并且上一个点是连通块内部的点,那么这个贪心一定没有后效性。

    因为 (b) 全为正所以随便找一条路径增广即可,现在的问题是找增广路,有一个 ( t naive) 的想法是直接 ( t dfs),如果 ( t dfs) 到了一个访问过的点就找到了增广路径(为了保证复杂度没有必要 ( t dfs) 时回到连通块),但是会有下面一种特殊情况:

    也就是我们先走红色的路径,但是因为 (a_v) 过大所以走不到绿色点,但是先走绿色路径却能先走到红色点。这种情况也是可以处理的,虽然 ( t dfs) 的时候先走的红色路径,但实际上我们会先走 (sum b) 大的那条路径。

    最外面需要套个二分,时间复杂度 (O(nmlog a))

    三、总结

    难以记录状态的图论题可以考虑增广的思路,连通图的耳分解也是类似增广的思路。

    如何去除贪心的后效性是个问题,感觉本题的这个方法有点构造的意思

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int M = 1005;
    const int inf = 0x3f3f3f3f;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int T,n,m,ans,a[M],b[M],vis[M],cur[M],pre[M];
    vector<int> g[M];
    int path(int x)
    {
    	if(vis[x]) return 0;vis[x]=1;
    	return min(inf,path(pre[x])+b[x]);
    }
    int dfs(int u,int x)
    {
    	x=min(inf,x+b[u]);
    	cur[u]=1;
    	for(auto v:g[u])
    	{
    		if(v==pre[u] || x<=a[v]) continue;
    		if(cur[v]) return path(u)+path(v);
    		pre[v]=u;int f=dfs(v,x);
    		if(f!=-1) return f;
    	}
    	return -1;
    }
    int check(int x)
    {
    	int f=0;
    	memset(vis,0,sizeof vis);
    	vis[1]=1;
    	while(f!=-1)
    	{
    		f=-1;
    		memcpy(cur,vis,sizeof cur);
    		for(int u=1;u<=n && f==-1;u++) if(vis[u])
    			for(auto v:g[u]) if(!vis[v] && x>a[v])
    			{
    				pre[v]=u;f=dfs(v,x);
    				if(f!=-1) break;
    			}
    		if(f==-1)
    		{
    			for(int i=1;i<=n;i++)
    				if(!vis[i]) return 0;
    			return 1;
    		}
    		x=min(inf,x+f);
    	}
    	return 0;
    }
    void dich(int l,int r)
    {
    	if(l>r) return ;
    	int mid=(l+r)>>1;
    	if(check(mid))
    	{
    		ans=mid;
    		dich(l,mid-1);
    	}
    	else dich(mid+1,r);
    }
    void work()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++) g[i].clear(); 
    	for(int i=2;i<=n;i++) a[i]=read();
    	for(int i=2;i<=n;i++) b[i]=read();
    	for(int i=1;i<=m;i++)
    	{
    		int u=read(),v=read();
    		g[u].push_back(v);
    		g[v].push_back(u);
    	}
    	dich(0,inf);
    	printf("%d
    ",ans);
    }
    signed main()
    {
    	T=read();
    	while(T--) work();
    }
    
  • 相关阅读:
    MySQL中的事务
    MySQL中的锁
    MySQL查询更新所有满足条件的数据
    MySQL存储引擎
    MySQL架构
    MySQL中存储json格式数据
    Java反射破坏单例模式
    合唱队(华为OJ)
    Java实现生产者消费者问题
    Spring IOC + AOP 的实现
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15208983.html
Copyright © 2011-2022 走看看