这题AC的挺不容易的,花了很多时间,但是我觉得做完一道这种题能学到很多东西,绝对不是刷20道甚至是100道水题能比的~
这题的关键是在求出最小生成树之后求出去掉生成树任意一条边后剩下的两颗树的距离,可以证明这个距离就是最佳替换边的长度,而把原来最小生成树的边换成最佳替换边后所得到的生成树就是原图中去掉那条边的最小生成树,这个用反正法可以证明,如果新得到的树不是最小生成树可以推出原来的树也不是最小生成树,要画图我就不详细证了。
然后求两颗树之间的最小距离我是用树状dp实现的,挺麻烦的,dp的方法有很多,只要把复杂度控制在O(n2)之内就可以了~~
好吧,哥继续搞sgu了 ~
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<cmath>
#include<cassert>
#include<cstring>
#include<iomanip>
using namespace std;
#ifdef _WIN32
#define i64 __int64
#define out64 "%I64d\n"
#define in64 "%I64d"
#else
#define i64 long long
#define out64 "%lld\n"
#define in64 "%lld"
#endif
#define FOR(i,a,b) for( int i = (a) ; i <= (b) ; i ++)
#define FF(i,a) for( int i = 0 ; i < (a) ; i ++)
#define FFD(i,a) for( int i = (a)-1 ; i >= 0 ; i --)
#define S64(a) scanf(in64,&a)
#define SS(a) scanf("%d",&a)
#define LL(a) ((a)<<1)
#define RR(a) (((a)<<1)+1)
#define SZ(a) ((int)a.size())
#define PP(n,m,a) puts("---");FF(i,n){FF(j,m)cout << a[i][j] << ' ';puts("");}
#define pb push_back
#define CL(Q) while(!Q.empty())Q.pop()
#define MM(name,what) memset(name,what,sizeof(name))
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
const int inf = 0x3f3f3f3f;
const i64 inf64 = 0x3f3f3f3f3f3f3f3fLL;
const double oo = 10e9;
const double eps = 10e-10;
const double pi = acos(-1.0);
const int maxn = 3011;
struct zz
{
int from;
int to;
int cost;
bool operator < (const zz & cmp ) const
{
return cost > cmp.cost;
}
}zx;
priority_queue<zz>q;
vector<zz>g[maxn];
vector<int>t[maxn];
bool hash[maxn][maxn];
bool vis[maxn];
bool ist[maxn][maxn];
bool fd[maxn][maxn];
int d[maxn][maxn];
int dp[maxn][maxn];
int ex[maxn];
int f[maxn];
int n,m,qq;
int mst;
void init()
{
FF(i,maxn)
{
g[i].clear();
t[i].clear();
}
CL(q);
MM(hash,false);
MM(fd,false);
return ;
}
int prim()
{
int ans = 0;
CL(q);
MM(vis,false);
MM(f,-1);
MM(ist,false);
vis[0]=true;
FF(i,g[0].size())
{
q.push(g[0][i]);
}
int now,to;
int temp;
FOR(i,1,n-1)
{
while(true)
{
zx = q.top();
q.pop();
if(vis[zx.to])
{
continue;
}
f[zx.to] = zx.from;
ans += zx.cost;
ist[zx.from][zx.to] = ist[zx.to][zx.from] = true;
t[zx.from].push_back(zx.to);
vis[zx.to]=true;
now = zx.to;
FF(i,g[now].size())
{
to = g[now][i].to;
if(!vis[to])
{
q.push(g[now][i]);
}
}
break;
}
}
return ans;
}
void dfs(short now)
{
vis[now] = true;
short i;
for(i=0;i<n;i++) if(vis[i])
{
fd[now][i] =true;
}
short to;
for(i=0;i<g[now].size();i++)
{
to = g[now][i].to;
if(!vis[to] && f[to]!=now)
{
dp[now][to] = g[now][i].cost;
}
}
for(i=0;i<t[now].size();i++)
{
to = t[now][i];
dfs(to);
}
vis[now]=false;
return ;
}
int dpst(short now,short id)
{
short to;
if(fd[id][now])
{
FF(i,t[now].size())
{
to = t[now][i];
dpst(to,id);
}
}
else
{
int temp = inf;
FF(i,t[now].size())
{
to = t[now][i];
temp = min( dpst(to,id) , temp );
}
dp[id][now] = temp = min(dp[id][now],temp);
return temp;
}
}
void final()
{
FF(i,n) FF(j,n) if(!fd[j][i])
{
ex[i] = min(ex[i],dp[j][i]);
}
return ;
}
void start()
{
FF(i,maxn) ex[i] = inf;
mst = prim();
FF(i,maxn) FF(j,maxn)
{
dp[i][j] = inf;
}
MM(vis,false);
dfs(0);
FF(i,n)
{
dpst(0,i);
}
final();
return ;
}
int main()
{
while(cin>>n>>m)
{
if(!n && !m)
{
break;
}
init();
FF(i,m)
{
SS(zx.from);
SS(zx.to);
SS(zx.cost);
hash[zx.from][zx.to] = hash[zx.to][zx.from] = true;
d[zx.from][zx.to] = d[zx.to][zx.from] = zx.cost;
g[zx.from].push_back(zx);
swap(zx.from,zx.to);
g[zx.from].push_back(zx);
}
start();
cin>>qq;
int x,y,z;
double ans=0.0;
double add;
double qx = qq;
while(qq--)
{
SS(x);
SS(y);
SS(z);
if(!ist[x][y])
{
ans += mst;
}
else
{
if(f[x] == y)
{
add = min(ex[x],z) - d[x][y];
}
else
{
add = min(ex[y],z) - d[x][y];
}
ans += add + mst;
}
}
ans /= qx;
printf("%.4lf\n",ans);
}
return 0;
}
分享到:
相关推荐
算法设计与分析实验六:使用动态规划算法解决存钱问题(java实现、hdu1114)(csdn)————程序
hdu ACM 高级程序设计习题集——全文 里面有程序的详细解释
杭电hdu acm资料所用杭电的acm题
本压缩包内包含杭电ACM集训的课件PPT,较为详细的介绍了动态规划,计算几何,贪心算法, 搜索,二分图及其应用,母函数及其应用,组合博弈入门,并查集,递推求解等常用算法
hdu acm 教案 搜索入门 hdu acm 教案 搜索入门
ACM HDU 2000->2099 解题报告 ACM HDU 2000->2099 解题报告 ACM HDU 2000->2099 解题报告
ACM HDU题目分类,我自己总结的大概只有十来个吧
hdu acm 教案 动态规划(1) hdu acm 教案 动态规划(1)
自己做的HDU ACM已经AC的题目
收集的部分HDOJ杭电ACM题的代码 大牛勿下 全是基础供初级acmer使用
acm 技术大牛 课件 HDU 自学必备课件 全套齐全 (lecture_01)初识ACM (lecture_02)简单数学题 (lecture_03)递推求解 (lecture_04)动态规划(1)_ (lecture_05)计算几何基础_ (lecture_06)母函数 (lecture_...
杭电ACMhdu1163
此程序为hdu的acm2010题,就是解决水仙花数问题
这是HDU acm 其中一部分题的代码,后续代码会继续上传。
hdu-acm源代码(上百题)hdu-acm源代码、hdu-acm源代码hdu-acm源代码
HDU的ACM,非常的好 涉及了很多算法,例如二分匹配、博弈、组合、最小生成树、搜索、动态规划、贪心算法
HDU 的ACM 题目,只做了一些简单的,都是用JAVA语言写的
ACM培训好资料!能帮助你快速提高ACM AC题目的能力,值得一下