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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章