明显的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了。。。