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了。。。
<think>好的,我现在需要处理用户关于数据库中的“relation”概念的问题。首先,用户提到了几个引用,我需要先仔细阅读这些引用内容,确保准确理解其中的信息。 根据引用[1],关系模式是型,关系是值,关系是元组的集合,关系模式描述结构,包括属性和域。引用[2]提到关系是表格之间的关联,通过外键建立。引用[3]强调了关系模型的优势,如数据独立性、减少冗余、支持复杂查询和数据完整性。引用[4]则说明关系有三种类型:基表、查询表和视图表,并指出关系对应二维表。 用户的问题集中在relation的概念、表结构和关系模型上。我需要将这些信息整合成结构化的回答,分点解释relation的定义、表结构组成、关系模型特点以及应用场景。同时,确保使用正确的中文表达,行内公式用$...$,独立公式用$$...$$,但根据用户的问题内容,可能涉及数学表达的地方较少,但如果有的话要注意格式。 接下来需要生成相关问题,这些问题应围绕用户提到的概念展开,比如关系模式与关系的区别、外键的作用、关系模型的优势、基表与视图表的区别等。确保问题相关且有深度,能够帮助用户进一步学习。 同时,检查是否有需要引用标记的地方,比如引用中的观点要在回答末尾自然添加[^1]、[^2]等。例如,当提到关系模式时,引用[1]中的内容需要标注;谈到表间关联时引用[2]等。 最后,确保回答符合用户要求的层级结构,先解释relation,再表结构,然后关系模型,最后应用场景。每个部分简洁明了,使用列表或分点方式,使内容清晰易读。同时避免使用Markdown格式,但根据用户提供的示例,可能需要使用代码块表示示例表结构,如用三个反引号包裹的表格示例。 总结步骤: 1. 确定用户的核心问题:relation的概念、表结构、关系模型。 2. 整合四个引用中的相关信息,分点组织内容。 3. 使用正确的LaTeX格式,尽管当前问题可能涉及较少数学公式,但仍需注意。 4. 生成相关问题,确保覆盖用户可能感兴趣的扩展方向。 5. 检查引用标记,确保每个引用来源正确标注。 6. 保持回答结构清晰,语言简洁,符合中文表达习惯。</think>### 数据库中 Relation 的概念与用法 #### 1. **Relation 的定义** 在关系模型中,**relation**(关系)是一个核心概念,逻辑上对应一张二维表。例如,一个学生信息表可表示为: ``` 学生表(学号, 姓名, 年龄, 专业) ``` 每个关系包含: - **属性(列)**:如学号、姓名等,定义数据的结构。 - **元组(行)**:具体的数据记录,如 `(1001, "张三", 20, "计算机科学")`。 - **域**:属性的取值范围,例如“年龄”域为整数[^1]。 关系模式(Relation Schema)是对关系的描述,例如: $$ \text{学生表}(学号: \text{字符串}, 姓名: \text{字符串}, 年龄: \text{整数}, 专业: \text{字符串}) $$ #### 2. **表结构与关系类型** - **基表(基本关系)**:实际存储数据的表,如上述学生表[^4]。 - **视图表**:通过查询或计算生成的虚拟表,例如: ```sql CREATE VIEW 计算机学生 AS SELECT 学号, 姓名 FROM 学生表 WHERE 专业 = '计算机科学'; ``` - **查询表**:临时存储查询结果的表。 #### 3. **关系模型的特点** - **数据独立性**:逻辑结构与物理存储分离,例如修改表结构无需调整底层存储[^3]。 - **减少冗余**:通过外键关联表,例如课程表引用学生表的学号: ``` 选课表(课程号, 学号, 成绩) ``` 此处“学号”是外键,建立表间关联[^2]。 - **数据完整性**:通过约束(如主键唯一性)确保数据准确。 #### 4. **应用场景** - **复杂查询**:利用 SQL 实现多表联合查询,例如: ```sql SELECT 学生表.姓名, 选课表.成绩 FROM 学生表 JOIN 选课表 ON 学生表.学号 = 选课表.学号; ``` - **数据规范化**:通过分解表消除冗余,例如将“学生-课程”数据拆分为学生表和选课表。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值