hdu6611 K Subsequence dijkstra版费用流

http://acm.hdu.edu.cn/showproblem.php?pid=6611

建图很水,就源点连向子源点一个(k,0)的边,每盘菜拆点,子源点连向左边每个(1,0),每个菜左点右点之间连个(1,-a[i]),右点连汇点(1,0)。

然而这题恶心之处在于时间只有2s,空间只有64mb,而有4e6条边,只能用vector存边。

而且据说枚举一个点所有边是连续的内存所以比前向星要在边表上跳跃快一些

稠密图所以要用dij费用流

在只有负边无负环的情况,允许重入队的dij最慢也不会比spfa慢。两种写法,直接用允许重入队的dij,就不用spfa预处理。如果用spfa预处理,就不用重入队的dij。区别只在第一次有负边的时候,后面算出了h保证所有边权>=0,两种dij写法就一样了。

所以似乎直接用重入队的dij写好些?

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> p;

const int maxl=4010;
const int inf=2e9+1e8+10;

int n,m,k,cnt,S,T,ans;
int a[maxl],dis[maxl],h[maxl];
int frm[maxl],frme[maxl];
struct ed{int to,w,c,inv;};
vector <ed> e[maxl];
bool in[maxl];

inline void add(int u,int v,int w,int c)
{
	int i=e[u].size(),j=e[v].size();
	e[u].push_back(ed{v,w,c,j});
	e[v].push_back(ed{u,0,-c,i});
}

inline void prework()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	T=maxl-1;S=maxl-2;e[S].clear();e[T].clear();
	for(int i=0;i<=2*n;i++)
		e[i].clear();
	add(S,0,k,0);
	for(int i=1;i<=n;i++)
	{
		add(0,i,1,0);
		add(i,n+i,1,-a[i]);
		add(n+i,T,1,0);
		for(int j=i+1;j<=n;j++)
		if(a[i]<=a[j])
			add(i+n,j,1,0);
	}
}

inline bool dij()
{
    dis[S]=dis[T]=inf;
	for(int i=0;i<=2*n;i++)
		dis[i]=inf;
    priority_queue<p,vector<p>,greater<p> >q;
    dis[S]=0;q.push({dis[S],S});
    int u,v,l;p d;
    while(!q.empty())
    {
        d=q.top();q.pop();
        u=d.second;
        if(dis[u]!=d.first)
            continue;
        l=e[u].size();
        for(int i=0;i<l;i++)
        if(e[u][i].w)
        {
            v=e[u][i].to;
            if(in[v] || dis[v]<=dis[u]+e[u][i].c+h[u]-h[v])
                continue;
            dis[v]=dis[u]+e[u][i].c+h[u]-h[v];
            frm[v]=u;frme[v]=i;
            q.push({dis[v],v});
        }
    }
    return dis[T]<inf;
}

inline void mcf()
{
	int u,v,ee,x=inf;
	u=T;
	while(u!=S)
	{
		v=u;ee=frme[u];u=frm[u];
		x=min(x,e[u][ee].w);
	}
	u=T;
	while(u!=S)
	{
		v=u;ee=frme[u];u=frm[u];
		e[u][ee].w-=x;
		e[v][e[u][ee].inv].w+=x;
	}
	ans-=x*(dis[T]+h[T]);
}

inline void mainwork()
{
	ans=0;h[T]=0;
	for(int i=0;i<=2*n;i++) h[i]=0;
	while(dij())
	{
		mcf();
		for(int i=0;i<=2*n;i++)
			h[i]=(inf,h[i]+dis[i]);
		h[T]=min(inf,h[T]+dis[T]); 
	}
}

inline void print()
{
	printf("%d\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/107395693