「省选模拟赛」小奇挖矿 3
原题:「泉七培训-刘定峰」物流
「题目背景」
小奇在喵星系使用了无限非概率驱动的采矿机,以至于在所有星球上都采出了一些矿石,现在它准备建一些矿石仓库并把矿石运到各个仓库里。
「问题描述」
喵星系有n个星球,标号为1到n,星球以及星球间的航线形成一棵树。
所有星球间的双向航线的长度都为1。小奇要在若干个星球建矿石仓库,设立每个仓库的费用为K。对于未设立矿石仓库的星球,设其到一个仓库的距离为i,则将矿石运回的费用为Di。
请你帮它决策最小化费用。
「输入格式」
第一行2个整数n,K。
第二行n-1个整数,D1,D2,…Dn-1,保证Di<=Di+1。
接下来n-1行,每行2个整数x,y,表示星球x和星球y存在双向航线。
「输出格式」
输出一行一个整数,表示最小费用。
「样例输入」
8 10
2 5 9 11 15 19 20
1 4
1 3
1 7
4 6
2 8
2 3
3 5
「样例输出」
38
「样例解释」
在1,2号星球建立仓库。
「数据范围」
对于30%的数据 n<=15
另外另外20%的数据,每个星球至多与另外两个星球存在双向航线。
对于100%的数据 n<=200,0<=K,Di<=100000
题解
30%的数据n<=15
2^15搜索所有点设立/不设立仓库,每个点bfs得到最近点,计算费用
20%的数据是一条链
不用关心图的连边情况,fi = min{fj + w(j+1 ,i)}
在j+1到i中枚举一个点设立仓库,w(j+1 ,i)为该区间最小费用。复杂度n^3
对于100%的数据
设计状态f(u,Cu)表示距离u的最近仓库为Cu(未建)时,u子树所有点的费用和。
转移时只要枚举结点u的所有儿子,假设当前处理的是儿子v,如果距离v的最近仓库也是Cu,那么直接用f(v,Cu);否则意味着子树v的内部有一个仓库Cv离v最近,那么枚举Cv,转移时再加上设立仓库Cv的费用
取f(1,C1)的最小值+K即为答案。
50分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#include<iostream> #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<ctime> #define ll long long #define inf 0x7fffffff using namespace std; //---------------------------------------------------------------- inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } //----------------------------------------------------------------快速读入 int n,K,cnt,sum; int mn=inf; int f[505],d[505],head[505],q[505],step[505]; bool used[505],vis[505]; struct data{int to,next;}e[1005]; void ins(int u,int v) { e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt; e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt; } int bfs(int x) { memset(vis,0,sizeof(vis)); int t=0,w=1; q[t]=x;vis[x]=1; while(t!=w) { int now=q[t],s=step[t];t++; for(int i=head[now];i;i=e[i].next) if(!vis[e[i].to]) { vis[e[i].to]=1; if(used[e[i].to])return s+1; else {step[w]=s+1;q[w++]=e[i].to;} } } return -1; } void getans() { int ans=sum; for(int i=1;i<=n;i++) { if(used[i])continue; int t=bfs(i); if(t!=-1)ans+=d[t]; else return; } mn=min(ans,mn); } void dfs(int k) { if(k==n+1){getans();return;} used[k]=1;sum+=K; dfs(k+1); used[k]=0;sum-=K; dfs(k+1); } int cal1(int x,int y) { int sum=0; for(int i=x;i<=y;i++) sum+=min(d[i-x],d[y-i]); return sum; } int cal2(int x) {int sum=0;for(int i=x+1;i<=n;i++)sum+=d[i-x];return sum;} int cal3(int x) {int sum=0;for(int i=1;i<x;i++)sum+=d[i];return sum;} void solve() { for(int i=1;i<=n;i++)f[i]=1000000000; for(int i=1;i<=n;i++) { f[i]=cal3(i); for(int j=i-1;j;j--) f[i]=min(f[i],f[j]+cal1(j,i)); f[i]+=K; mn=min(mn,f[i]+cal2(i)); } printf("%d",mn); } int main() { freopen("mining.in","r",stdin); freopen("mining.out","w",stdout); n=read();K=read(); for(int i=1;i<n;i++) d[i]=read(); if(n>15){solve();return 0;} for(int i=1;i<n;i++) { int u=read(),v=read(); ins(u,v); } dfs(1); printf("%d",mn); return 0; } |
100分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
#include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define LL long long #define inf 1000000000 using namespace std; LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,K,cnt; int d[205],last[205],dis[205][205],f[205][205]; struct edge{ int to,next; }e[405]; void insert(int u,int v) { e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt; e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt; } void getdis(int u,int v,int fa,int d) { dis[u][v]=d; for(int i=last[v];i;i=e[i].next) if(e[i].to!=fa) getdis(u,e[i].to,v,d+1); } void dp(int x,int fa) { for(int i=1;i<=n;i++) f[x][i]=d[dis[x][i]]; for(int i=last[x];i;i=e[i].next) if(e[i].to!=fa) { dp(e[i].to,x); int mn=inf; for(int j=1;j<=n;j++) mn=min(mn,f[e[i].to][j]+K); for(int j=1;j<=n;j++) f[x][j]+=min(mn,f[e[i].to][j]); } } int main() { freopen("mining.in","r",stdin); freopen("mining.out","w",stdout); n=read();K=read(); for(int i=1;i<=n-1;i++) d[i]=read(); for(int i=1;i<n;i++) { int u=read(),v=read(); insert(u,v); } for(int i=1;i<=n;i++) getdis(i,i,0,0); dp(1,0); int ans=inf; for(int i=1;i<=n;i++) ans=min(ans,f[1][i]+K); printf("%d\n",ans); return 0; } |