hdu4126 prim+树形dp

Genghis Khan(成吉思汗)(1162-1227), also known by his birth name Temujin(铁木真) and temple name Taizu(元太祖), was the founder of the Mongol Empire and the greatest conqueror in Chinese history. After uniting many of the nomadic tribes on the Mongolian steppe, Genghis Khan founded a strong cavalry equipped by irony discipline, sabers and powder, and he became to the most fearsome conqueror in the history. He stretched the empire that resulted in the conquest of most of Eurasia. The following figure (origin: Wikipedia) shows the territory of Mongol Empire at that time. 

Our story is about Jebei Noyan(哲别), who was one of the most famous generals in Genghis Khan’s cavalry. Once his led the advance troop to invade a country named Pushtuar. The knights rolled up all the cities in Pushtuar rapidly. As Jebei Noyan’s advance troop did not have enough soldiers, the conquest was temporary and vulnerable and he was waiting for the Genghis Khan’s reinforce. At the meantime, Jebei Noyan needed to set up many guarders on the road of the country in order to guarantee that his troop in each city can send and receive messages safely and promptly through those roads. 

There were N cities in Pushtuar and there were bidirectional roads connecting cities. If Jebei set up guarders on a road, it was totally safe to deliver messages between the two cities connected by the road. However setting up guarders on different road took different cost based on the distance, road condition and the residual armed power nearby. Jebei had known the cost of setting up guarders on each road. He wanted to guarantee that each two cities can safely deliver messages either directly or indirectly and the total cost was minimal. 

Things will always get a little bit harder. As a sophisticated general, Jebei predicted that there would be one uprising happening in the country sooner or later which might increase the cost (setting up guarders) on exactly ONE road. Nevertheless he did not know which road would be affected, but only got the information of some suspicious road cost changes. We assumed that the probability of each suspicious case was the same. Since that after the uprising happened, the plan of guarder setting should be rearranged to achieve the minimal cost, Jebei Noyan wanted to know the new expected minimal total cost immediately based on current information. 

题意就是说给一个图,给多组询问,每次询问会找出一个可疑边并给一个更长的边替换掉这条可疑边,每次问最小生成树的值,输出所有询问的最小生成树平均值。

貌似是某区域赛原题,很难的样子。预处理肯定是先跑一遍最小生成树了。然后如果某条可疑边没有在最小生成树里,那答案就是最小生成树的值了。

如果在生成树里呢,那就两种情况,先断开该边变成两棵树,找到连这两棵树的最小边长度即可。

问题在于求边。数据范围来看,求最小边长肯定是预处理了,用树形dp,处理掉两点间如果断开所能连接的最小长度。

最后每次询问找到长边与该最小长度的最小值即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#include<queue>
#include<vector>
using namespace std;
const int N=3010;
const int inf=0x3f3f3f3f;
int mp[N][N];
int k,vis[N],n,sum;
int dis[N]={0};
//int used[N][N];
int pre[N];
int dp[N][N];
vector<int> v[N];
void prim() ///prim模版
{
    sum=0;
    //memset(used,0,sizeof(used));
    memset(vis,0,sizeof(vis));
    dis[0]=inf;
    vis[0]=1;
    for(int i=1;i<n;i++)
	{
		dis[i]=mp[0][i];
		pre[i]=0;
	}
	pre[0]=-1;
	for(int i=1;i<n;i++)
	{
		int minn=inf;
		int t=-1;
		for(int j=1;j<n;j++)
		{
			if(!vis[j]&&dis[j]<minn)
			{
				minn=dis[j];
				t=j;
			}
		}
		vis[t]=1;
		if(t!=-1)
		{
			sum+=dis[t];
			if(pre[t] != -1)
            v[t].push_back(pre[t]),
            v[pre[t]].push_back(t);
			for(int j=1;j<n;j++)
			{
				if(!vis[j]&&dis[j]>mp[t][j])
				{
					dis[j]=min(dis[j],mp[t][j]);
					pre[j]=t;
				}
			}
		}
	}
}
int dfs(int root,int pos,int father)
{
	int ans=inf;
	for(int i=0;i<v[pos].size();i++)
	{
		int to=v[pos][i];
		if(to==father) continue; //防止死循环
			int tmp=dfs(root,to,pos);//每次递归寻找自己的孩子节点的值
						//注意这里,dfs所得到的结果是他的所有孩子节点中与root连接的最小值
			ans=min(ans,tmp);
			dp[pos][to]=dp[to][pos]=min(dp[to][pos],tmp);
	}
	  if(root != father)///如果相等,那么该边即为最小生成树上的边,肯定不行
        ans = min(ans,mp[root][pos]);
	return ans;
}
int main()
{
	int T,x,y,t,u,w,m,q;
	while(scanf("%d %d",&n,&m)!=EOF&&(n+m))
	{
		memset(mp,inf,sizeof(mp));
		memset(dp,inf,sizeof(dp));
		for(int i=0;i<n;i++)
			v[i].clear();
		for(int i=0;i<m;i++)
		{
			scanf("%d %d %d",&x,&y,&w);
			mp[x][y]=mp[y][x]=w;
		}
		prim();
		for(int i=0;i<n;i++)
			dfs(i,i,-1);
		scanf("%d",&q);
		double ans=0;
		for(int i=0;i<q;i++)
		{
			scanf("%d %d %d",&x,&y,&w);
			if(pre[x]!=y&&pre[y]!=x)
			{
				ans+=sum*1.0;
			}
			else
			{
				ans+=sum*1.0-mp[x][y]+min(dp[x][y],w);
				//printf("ans : %f\n",ans);
			}
		}
		printf("%.4f\n",ans/q);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值