二分图匹配 求最大独立集
把不好惹的同学的行和列连边,并分别放入二分图的两个集合中。
因为不好惹同学的行和列只能任选其一,而我们要使选出的所有行和列总和最大,就用选出的所有的行和列总数减去最小的不选的行和列的总数(最小点覆盖)。
又 最大独立集=n-最小点覆盖=n-最大匹配数。
所以用匈牙利算法求一遍最大匹配数,再用总的行列数减去就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005,inf=0x3f3f3f3f;
int n,m,x,y,match[N],v[N],head[N],ans,tot,sum;
struct edge{
int ver,to;
}e[N*N];
void add(int x,int y)
{
e[++tot].ver=y;
e[tot].to=head[x];
head[x]=tot;
}
int read()
{
int sum=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
void print(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)print(x/10);
putchar(x%10+'0');
}
int dfs(int x)
{
for(int i=head[x];i;i=e[i].to)
{
int y=e[i].ver;
if(v[y])continue;
v[y]=1;
if(!match[y]||dfs(match[y]))
{match[y]=x;return 1;}
}
return 0;
}
int main(){
// freopen("phalanx.in","r",stdin);
// freopen("phalanx.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;i++)
{
x=read();y=read();
add(x,y);
}
for(int i=1;i<=n;i++)
{
memset(v,0,sizeof(v));
if(dfs(i))sum++;
}
ans=(n*2-sum)*n;
print(ans);
return 0;
}
翻译一下题目的运算符,就是**(a+b)/2**
区间DP:f[i] [j] [x]=0/1表示i到j这段区间是否能合成x
枚举区间的左右端点i,j,区间[1,k]的数字l,区间[k+1,j]的数字r
状态转移方程:f[i] [j] [(l+r)/2]|=f[i] [k] [l]&f[k+1] [j] [r]
mn表示所有数中最大的数
答案:若f[1] [n] [k]=1 则输出k (0<=k<=mn)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005,inf=0x3f3f3f3f;
int n,ans[N],f[N][N][8],mn,x,tot;
int read()
{
int sum=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
void print(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)print(x/10);
putchar(x%10+'0');
}
int main(){
// freopen("math.in","r",stdin);
// freopen("math.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)
{
x=read();
mn=max(mn,x);
f[i][i][x]=1;
}
for(int i=n;i>=1;i--)
for(int j=i+1;j<=n;j++)
for(int k=i;k<j;k++)
for(int l=0;l<=mn;l++)
for(int r=0;r<=mn;r++)
f[i][j][(l+r)>>1]|=f[i][k][l]&f[k+1][j][r];
for(int i=0;i<=mn;i++)
if(f[1][n][i])ans[++tot]=i;
for(int i=1;i<=tot;i++)
{
print(ans[i]);
if(j!=tot)putchar(' ');
}
return 0;
}
贪心
[x,y]:查询的区间
x0:初始愉悦度
i:当前的景点。
now:当前这一段连续区间的值。
ans最终答案
若p[i] 否则 now=min(now+d[i],p[i]);(愉悦度不能超过每个景点愉悦度上限) 最后 ans=max(ans,now);代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=40005,inf=0x3f3f3f3f;
int n,d[N],p[N],x0,x,y,ans,now,q,f;
int read()
{
int sum=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
void print(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)print(x/10);
putchar(x%10+'0');
}
int main(){
// freopen("park.in","r",stdin);
// freopen("park.out","w",stdout);
n=read();q=read();
for(int i=1;i<=n;i++)
d[i]=read();
for(int i=1;i<=n;i++)
p[i]=read();
while(q--)
{
x=read();y=read();x0=read();
now=x0;
ans=0;
for(int i=x;i<=y;i++)
{
if(p[i]<x0){now=x0;continue;}
now=min(now+d[i],p[i]);
ans=max(ans,now);
}
print(ans);
putchar('\n');
}
return 0;
}