HDU 4081(次小生成树)
题意:这题是给你n个点坐标,m条边,然后让你连成一棵生成树,可以把其中一条边的权值变为0,然后求这条边两端点的权值之和/(生成树权值-这条边权)最大值
题解:这得枚举删除每一条边啊,然后求含有这条边的最小生成树
看了题解之后才明白这是求次小生成树(用prim算法),先求MST,并且记录下哪条边是MST中的,然后枚举MST中的边(p1+p2)/(MST-edge)
如果这条边不是MST中的,但是要求含有这条边的MST,那么将这条边连入MST中,去掉可以去掉的边种权值最大的,不就是含有这条边的MST么
如何来求这个可以去掉的权值最大的边,如果代替他的边,连接a,b,那么a,b原本就是一棵树上的,就找a,b之间的最大边,记为path[a][b]
path[a][b]=max(path[a][pre[b]],edge[pre[b]][a])
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define MAX 1000+5 #define MAXN 100000+5 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define mid int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem0(x) memset(x,0,sizeof(x)) #define mem1(x) memset(x,-1,sizeof(x)) #define meminf(x) memset(x,INF,sizeof(x)) #define lowbit(x) (x&-x) const int mod = 1000000007; const int prime = 999983; const int INF = 0x3f3f3f3f; const int INFF = 1e9; const double pi = 3.141592653589793; const double inf = 1e18; const double eps = 1e-10; //读入外挂 inline int read_int(){ int ret=0; char tmp; while(!isdigit(tmp=getchar())); do{ ret=(ret<<3)+(ret<<1)+tmp-'0'; } while(isdigit(tmp=getchar())); return ret; } struct Node{ double x,y,p; }node[MAX]; double edge[MAX][MAX]; double path[MAX][MAX]; double dis[MAX]; int vis[MAX]; int use[MAX][MAX]; int pre[MAX]; int n; double prim(){ mem0(path); mem0(vis); mem0(use); vis[1]=1; dis[0]=INF; double ans=0; for(int i=1;i<=n;i++){ dis[i]=edge[1][i]; pre[i]=1; } while(1){//prim算法 int x=0; for(int i=1;i<=n;i++){ if(!vis[i]&&dis[i]<dis[x]) x=i; } if(!x) break; vis[x]=1; ans+=dis[x]; use[pre[x]][x]=use[x][pre[x]]=1; for(int i=1;i<=n;i++){ if(!vis[i]&&dis[i]>edge[x][i]){//计算MST dis[i]=edge[x][i]; pre[i]=x; } else if(vis[i]&&i!=x){//计算x到前面每个点的路中的权值最大的边 path[i][x]=path[x][i]=max(path[i][pre[x]],edge[pre[x]][x]); } } } return ans; } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); mem0(edge); for(int i=1;i<=n;i++){ double a,b,c; scanf("%lf%lf%lf",&a,&b,&c); node[i]=(Node){a,b,c}; for(int j=1;j<i;j++){ double r=node[i].x-node[j].x; double s=node[i].y-node[j].y; double diss=sqrt(r*r+s*s); edge[i][j]=edge[j][i]=diss; } } double ans=prim(); double r=0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j) continue; if(use[i][j]){ r=max(r,(node[i].p+node[j].p)/(ans-edge[i][j]));//MST中的边 } else { r=max(r,(node[i].p+node[j].p)/(ans-path[i][j]));//不是MST中的边 } } } printf("%.2f\n",r); } return 0; }
题意:给一个DAG,求DAG的MST
题解:这题一开始以为很水u,结果WA
然后看了题解,最小树形图-朱刘算法(还是挺难的)
http://blog.csdn.net/wsniyufang/article/details/6747392
AC代码 : http://paste.ubuntu.net/12612008/