最小花费
1711:最小花费
时间限制: 1000 ms 内存限制: 262144 KB
【题目描述】
有n个未知数,每个数都是0或1,这些未知数已经按1到n编好了序。询问第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<N≤5
对于50%数据,2<N≤5
对于100%数据,2<N≤2000,1≤i≤j≤n,0≤c[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比克鲁斯卡尔算法要快!
___________________________________________________
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }