[JZOJ 1497] 景點中心 {樹形動態規劃}
阿新 • • 發佈:2019-02-07
題目
話說寧波市的中小學生在鎮海中學參加計算機程式設計比賽,比賽之餘,他們在鎮海中學的各個景點參觀。鎮海中學共有個景點,每個景點均有若干學生正在參觀。這個景點以自然數至編號,每兩個景點的編號均不同。每兩個景點之間有且只有一條路徑。選擇哪個景點集中的學生,才能使所有學生走過的路徑之和最小呢?
輸入檔案中有若干行:
第一行只有一個正整數,表示景點數。
第二行有個至間的整數,這個整數間互相以一個空格分隔。其中第i個整數表示第個景點處的學生數。
第三行至第行,每行有三個整數,表示景點i和景點j之間有一條長尾k的路徑直接連線。其中
輸出檔案center.out中有二行;
第一行只有一個整數i,表示在第i個景點處集中時,所有學生走過的路徑之和最短。
第二行也只有一個整數,表示所有學生走過的路徑之和的最小值
解題思路
分,考試程式碼,
分,正解,樹型動態規劃。只需先算出一次以1為根節點的樹的所有學生數量,和路徑。然後沿著這棵樹,求出假設子節點為“根節點”的樹時的值【一邊加,一邊減】。然後列舉求出最大值即可。
程式碼(30分)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[10001],x,y,t[10001][10001];
int main()
{
scanf("%d",&n);
memset(t,127/3,sizeof(t));
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=n-1;i++)
{
scanf("%d%d",&x,&y);
scanf("%d",&t[x][y]);
t[y][x]=t[x][y];
}
for (int m=1;m<=n;m++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) if(i!=j)
t[i][j]=min(t[i][j],t[i][m]+t[m][j]);
int ans=1e9,minn=-1;
for (int i=1;i<=n;i++)
{
int ma=0;
for (int j=1;j<=n;j++)
if (i!=j) ma+=a[j]*t[j][i];
if (ans>ma) {
minn=i; ans=ma;
}
}
printf("%d\n",minn);
printf("%d",ans);
}
程式碼(100分)
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int y,z,next;
}a[300011];
int n,len,last[100011],w;
long long size[100011],sum[100011],q;
void add(int xx,int yy,int zz)
{ a[++len].y=yy; a[len].z=zz; a[len].next=last[xx]; last[xx]=len; }
void dp(int g,int dep,int father)
{
size[g]=sum[g]*dep;//dep為到根節點的距離
for (int i=last[g];i;i=a[i].next)
if (a[i].y!=father)
{
dp(a[i].y,dep+a[i].z,g);
sum[g]+=sum[a[i].y]; //人數
size[g]+=size[a[i].y]; //目前節點路徑總和
}
}
void sdp(int g,int father)
{
for (int i=last[g];i;i=a[i].next)
if (a[i].y!=father)
{
size[a[i].y]=size[g]+(sum[1]-2*sum[a[i].y])*a[i].z; //換根
if (size[a[i].y]<q)
{
q=size[a[i].y];
w=a[i].y;
}
sdp(a[i].y,g);
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&sum[i]);
int xx,yy,zz;
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&xx,&yy,&zz);
add(xx,yy,zz); add(yy,xx,zz);
}
q=1e18;w=-1;
dp(1,0,0);
sdp(1,0);
if (size[1]<q)//落下的判斷
{
q=size[1];
w=1;
}
printf("%d\n%lld",w,q);
}