月考核補題
文章目錄
一、A.神奇的小石子
題目描述
斌斌翻水水的家鄉有很多個水井,每個水井 i 和其他水井 j 都有一個管子連通,這樣一個水井沒水的時候其他的水井可以通過水管直接輸送水過來,而這個管子的容量是vij,
有一天斌斌翻水水在野外燒烤的時候被一個奇異的小石頭砸中,當時斌斌翻水水就覺的這個石頭很特別就帶回了家,在多年的研究之下他發現這個石頭有個神奇的功能:
它能夠將多個水井劃分成兩個區域A和B,在同一個區域的水井之間不再需要水管連線,神奇的小石頭可以直接讓他們的水流通,但是在不同區域的水井卻不行,仍然需要水管相連線。
不能獨立在外),但是斌斌翻水水又很懶不想自己去想怎麼進行劃分,所以他把這個難題拋給了聰明的你,希望你能幫住到他。
Input
輸入一共N+1行,第一行為一個數字N(2 <= N <= 20),代表一共有幾個水井,接下去有N行數字,每行數字有N個數字,第i行數字的第j列數字代表Vij.(注意 vij = vji , vii = 0, 0 <= vij <= 10000)(例如樣例中的 0 50 30 的 50代表第一個水井和第二個水井之間的水管容量為50)
一共一行,那一行包含一個數字,代表斌斌翻水水讓你求的利用水管的最大容量總和。
樣例輸入
3
0 50 30
50 0 40
30 40 0
樣例輸出
90
提示
90的答案是這樣來的,將第一個水井和第三個水井放在A,將第二個水井放到B,那麼第一個水井和第三個水井和第二個水井之間的水管要連線那麼便是50+40 = 90。
雖然神奇的石頭擁有著超自然的力量,但是其他物質和現實生活中一樣,所以你無需考慮水管容量是負數的情況,只需要考慮水管是非負數的情況就行了。
思路:初始化定義所有水井在同一側(假設左側),列舉每一個水井,對其進行決策(轉移到右邊或者不轉移),更新最大體積
程式碼如下(示例):
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 50;
int a[N][N];
int v[N];
int n,maxn;
void dfs(int x,int w)//對x號石頭進行抉擇 ,類似01揹包思想
{
if(x==n+1){//所有石頭都已經抉擇完
if(w>maxn) maxn = w;
return ;
}
v[x]=1;//轉移x號石頭
int val=0;
for(int i=1;i<=n;i++)//對w體積改變進行增減
{
if(!v[i]) val+=a[x][i];
else val-=a[x][i];
}
dfs(x+1,w+val);
v[x]=0;//不轉移x號石頭
dfs(x+1,w);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
}
}
dfs(1,0);
cout<<maxn<<endl;
return 0;
}
二、B.序列樹
題目描述
在O. michestep王國,有一棵名叫Habaritran的樹,樹上有一個長度為 n 的序列 a,由於樹的營養不足,序列只由 0 和 1 構成,修理工Mitchell mitt覺得序列中每個連續的長度為 k 的子串中的0 與1 數量都相同,這棵樹才看起來很nice。當然,修理工Mitchell mitt可以將序列中任何一個 0 修改成 1,也可以將任何一個1修改為0,請問修理工Mitchell mitt最少需要修改多少次,才能將這棵樹變得nice。
Input
第一行包含兩個正整數,分別為 n和k
第二行包含 n個數,每個數為 0 或者 1
Output
輸出一行包含一個正整數,表示最少次數,如果序列怎麼修改都不能讓這棵樹變nice,那麼輸出"-1"(不包含引號)
樣例輸入
8 3
10100010
樣例輸出
-1
提示
資料範圍 1 <= k <= n <= 10^6
思路:
程式碼如下(示例):
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e6+10;
int n,k,ans;
char s[N];
struct node{
int a,b,r;
}p[N];
bool cmp(node x,node y)
{
return x.r<y.r;//對a-b升序
}
int main()
{
cin>>n>>k;
cin>>s;
if(k&1)
{
cout<<"-1";
return 0;
}
for(int i=0;i<k;i++)
{
for(int j=i;j<n;j+=k)
{
if(s[j]=='0') p[i].a++;//變為1需要的次數
else if(s[j]=='1') p[i].b++;//變為0需要的次數
}
p[i].r=p[i].a-p[i].b;
}
sort(p,p+k,cmp);
for(int i=0;i<k/2;i++) ans+=p[i].a;
for(int i=k/2;i<k;i++) ans+=p[i].b;
cout<<ans<<endl;
return 0;
}