2019.3.2 提高B组T4 SSL-1299 选做作业

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88078410

D e s c r i p t i o n Description

一些有价值的点,选了某个点之前要选某个点,求最大价值

数据范围:边数和点数均小于500


S o l u t i o n Solution

首先环是不能选的(显然)

基环树或树的情况直接拓扑排序去环后树形 d p dp ,这样的复杂度显然是 O ( n ) O(n)

但是我们通过观察数据范围,发现其实是允许 O ( n 3 ) O(n^3) 的做法过的,于是乎。。。

网络流大法好!

类似太空飞行计划问题,我们把选择某些点转换为放弃某些点,这就变成了一个最小割问题

正数左边,负数放右边

d i n i c dinic 算法轻松解决


C o d e Code

#include<queue>
#include<cstdio>
#include<vector>
#include<cctype>
#include<cstring>
#define N 511
#define M 250501
using namespace std;int n,rd[N],sum,s,t,v[N];
vector<int>g[N];
inline long long read()
{
    char c;int d=1;long long f=0;
    while(c=getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
char c;
bool flag;
struct node{int next,to,w;}e[M];
int l[N],tot,d[N];
bool vis[N];
void add(int u,int v,int w)
{
    e[tot]=(node){l[u],v,w};l[u]=tot++;
    e[tot]=(node){l[v],u,0};l[v]=tot++;
    return;
}
bool bfs()
{
    memset(d,-1,sizeof(d));
    queue<int>q;d[s]=0;q.push(s);
    while(q.size())
    {
        int x=q.front();q.pop();
        for(int i=l[x];~i;i=e[i].next)
        {
            int y=e[i].to;
            if(e[i].w&&d[y]==-1)
            {
                d[y]=d[x]+1;
                if(y==t) return true;
                q.push(y);
            }
        }
    }
    return false;
}
int dfs(int x,int flow)
{
    if(x==t||!flow) return flow;
    int rest=0,f=0;
    for(int i=l[x];~i;i=e[i].next)
    {
        int y=e[i].to;
        if(d[x]+1==d[y]&&e[i].w)
        {
            f=dfs(y,min(flow-rest,e[i].w));
            if(!f) d[y]=-1;
            e[i].w-=f;rest+=f;e[i^1].w+=f;
        }
    }
    if(!rest) d[x]=-1;
    return rest;
}
void dinic()
{
    while(bfs()) sum-=dfs(s,1e9);
    return;
}
inline void topsort()
{
    queue<int>q;
    int y,w;
    for(register int i=1;i<=n;i++) if(!rd[i]) q.push(i);
    while(q.size())
    {
        int x=q.front();q.pop();
        for(register int i=0;i<g[x].size();i++) if(!--rd[y=g[x][i]]) q.push(y);
    }
    return;
}
signed main()
{
	n=read();
	for(register int i=1;i<=n;i++)
	{
		v[i]=read();rd[i]=read();
		for(register int j=0;j<rd[i];j++) g[read()].push_back(i);
	}
	topsort();memset(l,-1,sizeof(l));s=n+1;t=n+2;
	for(register int i=1;i<=n;i++)
	{
		if(rd[i]) continue;
		if(v[i]<0) add(i,t,-v[i]);else add(s,i,v[i]),sum+=v[i];//先计算总和
		for(register int j=0;j<g[i].size();j++)
		{
			int k=g[i][j];
			if(rd[k]) continue;
			add(k,i,1e9);
		}
	}
	dinic();
	printf("%d",sum);//再减
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/88078410