WC 2011 relation

本文深入分析了树形动态规划的实现方式,并将其应用于寻找最大密度子图的问题中。通过实例讲解,展示了如何利用树形DP解决复杂问题,以及与最大密度子图求解的相关性。同时,提供了代码实现和具体应用示例,旨在提升读者在图论和算法领域的实践能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

明显的NPC或NP-hard,因为它是要在一个图中寻找一个K个点的导出子图,使其边权最大。。。如果这都可以在多项式中解决。。。那么寻找一个图中的k阶团就可解了。。。

point 3,4,5:明显的树形DP。。。三个维度F[i,j,s]表示i号点及其兄弟儿子。。。还剩j个点未选择。。。i的父亲选取状况为s(0为未选,1为已选)的最大权值。。。DFS记忆化搜索实现。。。吐槽一句。。。由于5号点K有1000+,这个程序是会跑的很慢的。。。一开始以为自己写丑了。。。后来膜拜各神犇程序后发现它就是跑的这么慢。。。啊啊啊。

point 9,10:原题明显与最大密度子图有关系。。。只不过限定了点集的阶。。。那么。。。可以猜测其中必有测试点的K正好是原图的最大密度子图的阶,所以9,10号点就可做了。。。具体最大密度子图求解看胡伯涛论文。。。

以下Code木有输出方案。。。我只是做着玩的。。。

Code:Tree_DP

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
typedef long long ll;
ll f[5005][2000][2];
int head[5005],next[10005],link[10005];
ll w[10005],liw[5005];
int son[5005],bro[5005];
int n=0,m=0,k=0,e=1;
bool vis[5005],view[5005][2000][2];
void dfs1(int s)
{
  vis[s]=1;
  for (int ne=head[s],y=link[ne];ne;ne=next[ne],y=link[ne])
    if (!vis[y])
      {
	liw[y]=w[ne];
	bro[y]=son[s];
	son[s]=y;
	dfs1(y);
      }
}
void dfs2(int s,int l,int c)
{
  view[s][l][c]=1;
  ll &ans=f[s][l][c];
  if (l==0) {ans=0;return;}
  int i=0;
  ll tmp=0;
  if (bro[s])
    {
      if (son[s])
	{
	  //Choose S
	  for (i=0;i<=l-1;i++)
	    {
	      if (!view[son[s]][i][1])
		dfs2(son[s],i,1);
	      if (!view[bro[s]][l-1-i][c])
		dfs2(bro[s],l-1-i,c);
	      tmp=f[son[s]][i][1]+f[bro[s]][l-1-i][c]+(ll)c*liw[s];
	      if (tmp>ans) ans=tmp;
	    }
	  //Abandon S
	  for (i=0;i<=l;i++)
	    {
	      if (!view[son[s]][i][0])
		dfs2(son[s],i,0);
	      if (!view[bro[s]][l-i][c])
		dfs2(bro[s],l-i,c);
	      tmp=f[son[s]][i][0]+f[bro[s]][l-i][c];
	      if (tmp>ans) ans=tmp;
	    }
	}
      else
	{
	  //Choose S
	  if (!view[bro[s]][l-1][c])
	    dfs2(bro[s],l-1,c);
	  ans=f[bro[s]][l-1][c]+(ll)c*liw[s];
	  //Abandon S
	  if (!view[bro[s]][l][c])
	    dfs2(bro[s],l,c);
	  tmp=f[bro[s]][l][c];
	  if (tmp>ans) ans=tmp;
	}
    }
  else
    {
      if (son[s])
	{
	  //Choose S
	  if (!view[son[s]][l-1][1])
	    dfs2(son[s],l-1,1);
	  tmp=f[son[s]][l-1][1]+(ll)c*liw[s];
	  if (tmp>ans) ans=tmp;
	  //Abandon S
	  if (!view[son[s]][l][0])
	    dfs2(son[s],l,0);
	  tmp=f[son[s]][l][0];
	  if (tmp>ans) ans=tmp;
	}
      else
	ans=(ll)c*liw[s];
    }
}
void add(int u,int v,ll tmpw)
{
  next[++e]=head[u];
  head[u]=e;
  link[e]=v;
  w[e]=tmpw;
  next[++e]=head[v];
  head[v]=e;
  link[e]=u;
  w[e]=tmpw;
}
int main()
{
  freopen("relation.in","r",stdin);
  freopen("relation.out","w",stdout);
  scanf("%d%d%d",&n,&m,&k);
  int u=0,v=0;
  ll tmpw=0;
  for (int i=1;i<=m;i++)
    {
      scanf("%d%d%I64d",&u,&v,&tmpw);
      add(u,v,tmpw);
    }
  dfs1(1);
  dfs2(1,k,0);
  printf("%I64d",f[1][k][0]);
  return 0;
}

Code:MDS

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
const double oo=10000000;
class network
{
private:
  double tot;
  int e,n,source,sink,top,tail;
  int next[23005],link[23005],head[1015],
    dis[1015],num[1015],pre[1015],now[1015],sta[4015];
  double w[23005],d[1015];
  void addspec(int u,int v,double tmpw)
  {
    next[++e]=head[u];
    head[u]=e;
    link[e]=v;
    w[e]=tmpw;
    next[++e]=head[v];
    head[v]=e;
    link[e]=u;
  }
  int remark(int &nopo)
  {
    int mindis=n-1;
    for (int ne=head[nopo];ne;ne=next[ne])
      if (w[ne]>0 && mindis>dis[link[ne]])
	mindis=dis[link[ne]];
    int tmp=dis[nopo];
    num[tmp]--;
    dis[nopo]=mindis+1;
    num[dis[nopo]]++;
    if (nopo!=source) nopo=pre[nopo];
    return num[tmp];
  }
  double getflow()
  {
    int nop=sink,prp=pre[sink];
    double flows=oo;
    for (;nop!=source;nop=prp,prp=pre[prp])
      if (w[now[prp]]<flows)
	flows=w[now[prp]];
    for (nop=sink,prp=pre[sink];nop!=source;nop=prp,prp=pre[prp])
      w[now[prp]]-=flows,w[now[prp]^1]+=flows;
    return flows;
  }
  void markbfs()
  {
    int ne=0,y=0,x=0;
    for (int i=1;i<n;i++) dis[i]=n;
    num[n]=n-1;
    dis[sink]=0;
    num[0]=1;
    top=0;
    sta[tail=1]=sink;
    while (top<tail)
      {
	x=sta[++top];
	for (ne=head[x],y=link[ne];ne;ne=next[ne],y=link[ne])
	  if ((!w[ne]) && dis[x]+1<dis[y])
	    {
	      num[dis[y]]--;
	      sta[++tail]=y;
	      dis[y]=dis[x]+1;
	      num[dis[y]]++;
	    }
      }
  }
public:
  double edgetot(){return tot;}
  void addnorm(int u,int v,double tmpw)
  {
    next[++e]=head[u];
    head[u]=e;
    link[e]=v;
    w[e]=tmpw;
    d[u]+=tmpw;
    next[++e]=head[v];
    head[v]=e;
    link[e]=u;
    w[e]=tmpw;
    d[v]+=tmpw;
    tot+=tmpw;
  }
  void build()
  {
    for (int i=1;i<=n-2;i++)
      {
	addspec(source,i,tot);
	addspec(i,sink,tot);
      }
  }
  void change(double key)
  {
    for (int ne=head[sink];ne;ne=next[ne])
      {
	w[ne^1]=tot+2*key-d[link[ne]];
	w[ne]=0;
      }
  }
  void refresh()
  {
    for (int i=2;i<=e;i++)
      if (i&1)
	{
	  w[i]+=w[i^1];
	  w[i]/=2;
	  w[i^1]=w[i];
	}
    for (int ne=head[source];ne;ne=next[ne])
      {
	w[ne]=tot;
	w[ne^1]=0;
      }
    for (int ne=head[sink];ne;ne=next[ne])
      {
	w[ne^1]+=w[ne];
	w[ne]=0;
      }
    memset(pre,0,sizeof(pre));
    memset(num,0,sizeof(num));
  }
  void creat(int node)
  {
    source=node+1;
    sink=node+2;
    n=node+2;
    e=1;
    memset(next,0,sizeof(next));
    memset(link,0,sizeof(link));
    memset(w,0,sizeof(w));
    memset(head,0,sizeof(head));
  }
  double maxflow()
  {
    double flow=0;
    markbfs();
    for (int i=1;i<=n;i++) now[i]=head[i];
    int ne=0,nopo=source;
    while (dis[source]<n)
      {
	for (ne=now[nopo];ne;ne=next[ne])
	  if (w[ne]>0 && dis[link[ne]]+1==dis[nopo])
	    break;
	if (ne)
	  {
	    now[nopo]=ne;
	    pre[link[ne]]=nopo;
	    nopo=link[ne];
	    if (nopo==sink)
	      {
		flow+=getflow();
		nopo=source;
	      }
	  }
	else
	  {
	    now[nopo]=head[nopo];
	    if (!remark(nopo))
	      break;
	  }

      }
    return flow;
  }
} net;
int main()
{
  freopen("relation.in","r",stdin);
  freopen("relation.out","w",stdout);
  int n=0,m=0,k=0;
  scanf("%d%d%d",&n,&m,&k);
  int i=0;
  net.creat(n);
  int u=0,v=0;
  double tmpw=0,f=0;
  double r=0;
  for (i=1;i<=m;i++)
    {
      scanf("%d%d%lf",&u,&v,&tmpw);
      net.addnorm(u,v,tmpw);
      if (tmpw>r) r=tmpw;
    }
  net.build();
  double l=0,mid=0;
  while (l+1e-5<r)
    {
      mid=(l+r)/2;
      net.change(mid);
      f=(net.edgetot()*n-net.maxflow())/2;
      if (f>0)
	l=mid;
      else
	r=mid;
      net.refresh();
    }
  f=l*(double)k;
  printf("%0.f",f);
  return 0;
}

现在喜欢上Class了。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值