最小花费

1711:最小花费


时间限制: 1000 ms         内存限制: 262144 KB

【题目描述】

n个未知数,每个数都是01,这些未知数已经按1n编好了序。询问第i个未知数到第j个未知数的和的奇偶性,需要付出一定费用。给出询问每个区间[i,j]的和的奇偶性的代价。你需要设计一个询问的方案,使得你能推断出这n个每个数的值,并使代价的总和最小。

【输入】

第一行一个整数n

i+1行(1≤i≤n)有n+1−i个整数,表示每一种询问所需的花费。

其中第i+1行第j+1−i个数c[i,j]表示对区间[i,j]进行询问的费用。

【输出】

输出一个整数,表示最少花费。

【输入样例】

3
1 2 3
2 2
1

【输出样例】

4

【提示】

【数据规模】

对于20%数据,2<N5

对于50%数据,2<N5

对于100%数据,2<N20001ijn0c[i,j]10^9

___________________________________________________

想要确定每一个数,实际就是确定sum[i]-sum[i-1]的值。这就相当于相邻两个点的距离。

我们要明白一点,想要确定sum[i]-sum[i-1]的值,这个值是可以用这两个点到其他点的距离进行计算的。如:sum[x]-sum[i]和sum[x]-sum[i-1]这两个值知道以后,我们就不需要在花费代价就可以计算出sum[i]-sum[i-1]的值。

这样实际上我们只需要通过算是把n个值连接起来就可以了!这不就是n+1个点建树嘛!而且要求代价最小,最小生成树!

最后:试了一下,由于是n*n级别的边数,所以prim比克鲁斯卡尔算法要快!

___________________________________________________

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=2010;
 4 int n;
 5 int md[maxn];
 6 bool bz[maxn];
 7 int dis[maxn][maxn];
 8 void  readint(int &x)
 9 {
10     int f=1;
11     char c=getchar();
12     for(;c>'9'||c<'0';c=getchar())if(c=='-')f=-1;
13     x=0;
14     for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
15     x=x*f;
16 }
17 long long ans;
18 
19 int main()
20 {
21     readint(n);
22     for(int i=1;i<=n;++i)
23         for(int w,j=i;j<=n;++j)
24         {
25             readint(w);
26             dis[i-1][j]=dis[j][i-1]=w;
27         }
28     memset(md,0x3f,sizeof md);
29     md[0]=0;
30     for(int i=0;i<=n;++i)
31     {
32         int mn=0x3f3f3f3f,no;
33         for(int j=0;j<=n;++j)
34             if(!bz[j]&&mn>md[j])mn=md[j],no=j;
35         bz[no]=1;ans+=mn;
36         for(int j=0;j<=n;++j)
37             if(!bz[j]&&md[j]>dis[no][j])
38                 md[j]=dis[no][j];
39     }
40     cout<<ans<<endl;
41     return 0;
42 }
View Code

 

posted on 2021-01-15 14:57  gryzy  阅读(435)  评论(0编辑  收藏  举报

导航