2011.07.18
来源:互联网 发布:p2p理财安全吗 知乎 编辑:程序博客网 时间:2024/05/01 17:19
POJ 1679 The Unique MST
题意:判断最小生成树的是否唯一
哎模板悲催的只有优先队列啊…然后就比较麻烦了,因为第一个入队列的点有相等的边会没法正确判断,我的解决方法很搓,就是找一条没有相等边的点当第一个点,万幸数据弱过了= =
模板上加了before[ ]记录每个点是被谁更新过,在遇到到树距离同样最短的边就判not unique……
#include<cstring>#include<algorithm>#include<queue>#include<fstream>#include<cstdio>#define MAXE 10000#define MAXV 105using 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 1001using 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;}
要是不是完全图会怎样呢?
嗷呜……让我做梦在去考虑吧……这种事……
- 2011.07.18
- 一个简单的媒体文件播放器 2011.07.18
- 2011.07.09
- 2011.07.11
- 2011.07.14
- 2011.07.15
- 2011.07.16
- 2011.07.17
- 2011.07.19
- 2011.07.20
- 2011.07.21
- 2011.07.22
- 2011.07.23
- 2011.07.24
- 2011.07.25
- 2011.07.26
- 2011.07.28
- 2011.07.29
- 黑马程序员 (9)JAVA高新技术 3
- 重叠IO
- android中的图形图像-访问图片drawable
- FI--关于凭证的修改和冲销操作
- patch
- 2011.07.18
- ibatis的remapResults属性
- C#程序调用GAMS
- 我们互联网生活因家庭服务器改变
- 用find_if查找vector内对象的成员
- How to change instance_number of RAC
- SPFA
- oracle 11g密码永不过期
- single linkList (draft)