POJ 1679 The Unique MST
题意:判断最小生成树的是否唯一
哎模板悲催的只有优先队列啊…然后就比较麻烦了,因为第一个入队列的点有相等的边会没法正确判断,我的解决方法很搓,就是找一条没有相等边的点当第一个点,万幸数据弱过了= =
模板上加了before[ ]记录每个点是被谁更新过,在遇到到树距离同样最短的边就判not unique……
#include<cstring>
#include<algorithm>
#include<queue>
#include<fstream>
#include<cstdio>
#define MAXE 10000
#define MAXV 105
using namespace std;
const int INF=(int)1<<31-1;
typedef pair<int,int> pii;
int t,m,n,V,E,pos=0,head[MAXV],num[MAXV],bian[MAXV];
int ans,d[MAXV];
struct Edge
{
int w,next,v,u;
}node[MAXE*2];
//无向图邻接表
void add(int u,int v,int w)
{
if(u==v) return; //如果指向自己的边则舍去
node[pos].u=u;
node[pos].v=v;
node[pos].w=w;
node[pos].next=head[u];
head[u]=pos++;
bian[u]++;
}
//S为起点标号
void prim(int b)
{
bool done[MAXV];
memset(done,0,sizeof(done));
int bf[MAXV];memset(bf,0,sizeof(bf));
priority_queue<pii,vector<pii>,greater<pii> > q;
q.push(make_pair(d[b],b));
while(!q.empty()){
pii u=q.top();q.pop();
int x=u.second;
if(done[x]) continue;
done[x]=true;
for(int i=head[x];i!=-1;i=node[i].next) //松弛操作
if(!done[node[i].v] && d[node[i].v]>node[i].w){
d[node[i].v]=node[i].w;
q.push(make_pair(d[node[i].v],node[i].v));
num[node[i].v]=0;bf[node[i].v]=x;
}
else if(bf[node[i].v]!=x && !done[node[i].v] && d[node[i].v]==node[i].w)
num[node[i].v]=1;
}
return ;
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int t=0,u,v,w,i,j;
bool can[100000];
scanf("%d",&t);
while(t--){
pos=1;
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
memset(bian,0,sizeof(bian));
scanf("%d%d",&V,&E);
if(E==0) {printf("0\n");continue;}
while(E--){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
for(i=1;i<=V;i++) d[i]=INF;
v=u;
for(i=1;i<=V;i++)if(bian[i]==1){v=i;break;}
for(i=1;i<=V;i++){
memset(can,0,sizeof(can));
for(j=head[i];j!=-1;j=node[j].next)
if(!can[node[j].w]) can[node[j].w]=1;
else break;
if(j==-1){ v=i;break;}
}
d[v]=0;
prim(v);
for(i=1;i<=V;i++){
ans+=d[i];
if(num[i]) break;
}
if(i>V) printf("%d\n",ans);
else printf("Not Unique!\n");
ans=0;
}
return 0;
}
嗯,对prim的理解有更多一点,哎,你还差得远呢,加油啊少年~这么说突然想到昨天学弟问我是不是有被叫过少年,哈哈~说起来,都是当学姐的人了…我真沧桑= =
POJ 2728
题意:求最优比率生成树:一个带权完全图,每条边都有自己的花费值cost[i]和收益值benifit[i],如果用x[i]来代表一条边取或不取(0/1问题),那么求一个生成树。要求:r=(∑cost[i]*x[i] ) / (∑benifit[i]*x[i] )最小。
本质上是0/1分数规划思想,对于上式可以变形为 z(r)=∑cost[i]*x[i] -r*∑benifit[i]*x[i]。而z(r)=0为我们所求。这里有个有意思的结论:z(r)为单调递减函数,因此是线性的。于是"我们可以兴高采烈地把z(r)看做以 cost[i]-r*benifit[i] 为边权的最小生成树的总权值"。抄过来三鲜的优美简明的结论~
1. z单调递减
证明: 因为cost为正数, 所以z随l的减小而增大.
2. z( max(r) ) = 0
证明: 若z( max(r) ) < 0, ∑(benifit[i] * x[i]) - max(r) * ∑(cost[i] * x[i]) < 0, 可化为 max(r) < max(r). 矛盾;
若z( max(r) ) >= 0, 根据性质1, 当z = 0 时r最大.
确定r有两种方法,二分和迭代(Dinkelbach)。二分方法上界用Σ(benifit[i]*x[i])/min(cost[i])确定,这是个不可能取到的足够大的值。Dinkelbach效率更高。
复杂度:时间 O( O(MST) * log max(r) );空间 O( O(MST) )
要是你不幸的忘掉了传送门:http://hi.baidu.com/zzningxp/blog/item/b2d1b4ec1f8bbc2262d09fc9.html
Dinkelbach详解:http://s99f.blog.163.com/blog/static/3511836520094291100110/
#include<fstream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define MAXE 10000
#define MAXV 1001
using namespace std;
const double inf=9999999;
double b[MAXV][MAXV],d[MAXV]; //b:benifit;c=cost;
int V,c[MAXV][MAXV],x[MAXV],y[MAXV],z[MAXV];
double tmp,ans;
double dis(int i,int j)
{
return sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(double)(y[i]-y[j])*(y[i]-y[j]));
}
double prim(double now)
{
bool done[MAXV];
int pre[MAXV],t,i,j;
double mini[MAXV],mm,C,B;
memset(done,0,sizeof(done));
d[1]=0;done[1]=1;
for(i=2;i<=V;i++){pre[i]=1;d[i]=c[1][i]-b[1][i]*now;}
for(int i=1;i<=V;i++){
mm=inf;
for(int j=1;j<=V;j++)
if(!done[j] && d[j]<mm){
mm=d[j];t=j;
}
C+=c[pre[t]][t];
B+=b[pre[t]][t];
done[t]=1;
for(int j=1;j<=V;j++){
if(d[j]>c[t][j]-b[t][j]*now){ //优先队列优化的prim会超时啊喂…
d[j]=c[t][j]-b[t][j]*now;
pre[j]=t;
}
}
}
return C/B;
}int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int i,j,k;
while(scanf("%d",&V)!=EOF,V){
int n=V;
for(i=1;i<=n;i++)
scanf("%d%d%d",&x[i],&y[i],&z[i]);
for(i=1;i<=V;i++)
for(j=1;j<=V;j++){
b[i][j]=b[j][i]=dis(i,j);
c[i][j]=c[j][i]=abs(z[i]-z[j]);
}
while(1){
tmp=prim(ans);
if(fabs(ans-tmp)<0.000001) break;
else ans=tmp;
}
printf("%.3lf\n",ans);
}
return 0;
}
要是不是完全图会怎样呢?
嗷呜……让我做梦在去考虑吧……这种事……