Description
魔術師的桌子上有n個杯子排成一行,編號爲1,2,…,n,其中某些杯子底下藏有一個小球,如果你準確地猜出是哪些杯子,你就可以獲得獎品。花費c_ij元,魔術師就會告訴你杯子i,i+1,…,j底下藏有球的總數的奇偶性。
採取最優的詢問策略,你至少需要花費多少元,才能保證猜出哪些杯子底下藏着球?
Input
第一行一個整數n(1<=n<=2000)。
第i+1行(1<=i<=n)有n+1-i個整數,表示每一種詢問所需的花費。其中c_ij(對區間[i,j]進行詢問的費用,1<=i<=j<=n,1<=c_ij<=10^9)爲第i+1行第j+1-i個數。
Output
輸出一個整數,表示最少花費。
Sample Input
5
1 2 3 4 5
4 3 2 1
3 4 5
2 1
5
Sample Output
7
題解:
沒有思路的可以先去看一下小胖的奇偶這道題。
知道了第x~y個杯子的奇偶性,就相當於知道了x和x-1之間的縫到y和y+1之間的縫的奇偶性,知道了縫a到縫b的奇偶性和縫b到縫c的奇偶性,我們就知道了縫a到縫c的奇偶性。要知道所有杯子底下有沒有球,我們就要知道每個杯子左右兩端的縫之間的奇偶性,也就相當於要知道任意兩個縫之間的奇偶性,所以這就是一道花式最小生成樹問題,知道奇偶性相當於連一條邊,整個圖聯通了就都能知道了。
代碼如下:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#define ll long long
#define N 2005
#define inf 0x7f7f7f7f
using namespace std;
int n,x;
int hd[N],tot,fa[N];
struct nod
{
int x,y,v;
nod(){}
nod(int a,int b,int c):x(a),y(b),v(c){}
inline bool operator<(const nod& rhs) const {return v<rhs.v;}
}e[N*N];
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n+1;i++) fa[i]=i;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
scanf("%d",&x);
e[++tot]=nod(i,j+1,x);
}
sort(e+1,e+tot+1);
ll ans=0,t=0;
for(int i=1;i<=tot;i++)
{
int fx=find(e[i].x),fy=find(e[i].y);
if(fx!=fy)
{
fa[fy]=fx;
ans+=e[i].v;
if(++t==n) break;
}
}
printf("%lld\n",ans);
return 0;
}