第一题:
第一题很简单,直接在输入之后,布尔类型数组相应的区域覆盖就可以了。
#include<iostream>
using namespace std;
bool a[1000005]; //布尔数组,表示是否有人在浇花
int n,t,y,maxx,maxn,maxe,ansn,anse,st=0xFFFFFF;
void in(int f,int g) //覆盖
{
for (int i=f;i<g;i++)a[i]=1;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for (int i=0;i<n;i++)
{
cin>>t>>y;
in(t,y);
maxx=max(maxx,y),st=min(st,t);
}
for (int i=st;i<maxx;i++)
{
if (a[i]==0)
{
maxn=0;
maxe++;
anse=max(maxe,anse);
}
else
{
maxe=0;
maxn++;
ansn=max(maxn,ansn);
}
}
cout<<ansn<<' '<<anse;
}
第二题:
本题主要的考察点是对于字符和数字间隔读入的处理。算法没有什么难度,唯一值得注意的在’/’的情况下,有可能会出现实数,所以不能用整数储存结果。
#include <iostream>
#include <cstdio>
using namespace std;
inline double abs(double x) {
if (x > 0) return x;
return -x;
}
int main()
{
int N, Best;
double Eps = 100000000, Value, Num1, Num2;
char Op;
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
scanf("%lf %c %lf", &Num1, &Op, &Num2);
switch (Op) {
case '+': Value = Num1 + Num2; break;
case '-': Value = Num1 - Num2; break;
case '*': Value = Num1 * Num2; break;
default : Value = Num1 / Num2;
}
Value = abs(Value - 9);
if (Value < Eps) {
Eps = Value;
Best = i;
}
}
printf("%d\n", Best);
return 0;
}
纯单源点最短路径
不多解释了,其实可以很短的……但是为了标程,还是写了一个堆优化的Dijkstra。
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
#define MAXN 5010
#define MAXM 500010
int n,m,dis[MAXN];
bool vis[MAXN];
struct Dis
{
int i,d;
bool operator>(const Dis &a) const{
return d>a.d;
}
};
struct node
{ int v,d;
node *next;}edge[MAXM];
node *cnt=&edge[0];
node *adj[MAXN];
void Addedge(int u,int v,int d)
{
node *p=++cnt;
p->v=v; p->d=d;
p->next=adj[u]; adj[u]=p;
}
void Dijkstra()
{
memset(dis,0x3f,sizeof(dis));
priority_queue<Dis ,vector<Dis>,greater<Dis> >q;
Dis e; e.i=1; e.d=0; dis[1]=0;
q.push(e);
while(!q.empty())
{
do
{
if(q.empty()) return;
e=q.top(); q.pop();
}while(vis[e.i]);
vis[e.i]=true;
if(e.i==n) break;
for(node *p=adj[e.i];p;p=p->next)
{
int v=p->v,d=p->d;
if(dis[e.i]+d<dis[v])
{
dis[v]=dis[e.i]+d;
Dis c; c.i=v; c.d=dis[v];
q.push(c);
}
}
}
}
int GET()
{
int num=0;
char ch;
do ch=getchar(); while(ch<'0' || ch>'9');
while('0'<=ch && ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num;
}
void Init()
{
m=GET();
for(int u,v,d,i=1;i<=m;i++)
{
u=GET();v=GET();d=GET();
Addedge(u,v,d);
}
}
int main()
{
if(scanf("%d",&n)==EOF) return 1;
if(n<2||n>5000) return 1;
Init();
Dijkstra();
printf("%d\n",dis[n]);
return 0;
}
第四题:
第四题是一个完全背包
#include<cstdio>
#include<iostream>
#define maxn 100
#define maxv 100000
#define MOD 999983
using namespace std;
int n,m;
int a[maxn+10],f[maxv+10];
void read()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
return;
}
void solve()
{
f[0]=1;
for(int i=1;i<=n;i++)
for(int k=0;k<=m-a[i];k++)
{
f[k+a[i]]+=f[k]; //状态转移方程
f[k+a[i]]%=MOD;
}
cout<<f[m]%MOD<<endl;
return;
}
int main()
{
read();
solve();
return 0;
}
第五题:
考察下面给出的三种情况:
1. 设t_max为所有t_i的最大值。不管其他的t_i的值为多少,FJ能够保证N-t_max个正确答案,他只需全部选择false。
2. 设t_min为所有t_i的最小值。不管其他的t_i值为多少,FJ能够保证t_min个正确答案,他只需全部选择true。
3. 将所有按从大到小排序,t_i设t_x 和 t_y是相邻的两个t_i(t_x>t_y),FJ可以保证(t_x-t_y)/2个正确答案,他只需选择N-[(t_x+t_y)/2]个正确答案,其余全部选择false。
这是一个例子:
|----->120
|--------->200
|---------------->340
|-------------------->420
|--------------------------------->680
|--------------------------------------->800
0 |----+----+----+----+----+----+----+----+----+----| 1000
总共有1000个题,答案为true的题分别为120,200,340,420,680,800,1000.我们将它们排序后,再来查看相邻的数据。
Case1:1000 - 800 = 200个正确答案可以保证,只需全部选false。
Case2:120个正确答案可以保证,只需要全部选true。
Case3:对于相邻的两个值420和680,(680 - 420) / 2 = 130个正确答案可以保证,只需要选择1000 - [(680 + 420) / 2] = 450个true。因为,如果有420个为true的答案,可以保证1000-420-450=130个false选择正确,而如果有680个true,也能保证有680+450-1000个true被选中。
现在,我们可以通过排序然后检查相邻值的差来解决这个问题。比较三种情形,找出其中最大的就行了。从上面这个例子,我们可以得到答案是200.
#include<stdio.h>
#include<algorithm>
int a[10005];
#define f(a,b) for(a=0;a<b;a++)
using namespace std;
int max(int a,int b){return a>b?a:b;}
int main()
{
int i,n,k,t;
scanf("%d%d",&n,&k);
f(i,k)scanf("%d",&t),a[i]=n-t;
sort(a,a+k);
int ans=a[0];
f(i,k-1)ans=max(ans,(a[i+1]-a[i])/2);
ans=max(ans,(n-a[k-1])/2);
printf("%d",ans);
}
第六题:
最少费用最大流
【问题分析】
二分图最佳匹配问题,可以费用流解决(或KM算法)。
【建模方法】
把所有人看做二分图中顶点Xi,所有工作看做二分图中顶点Yi,建立附加源S汇T。
1、从S向每个Xi连一条容量为1,费用为0的有向边。
2、从每个Yi向T连一条容量为1,费用为0的有向边。
3、从每个Xi向每个Yj连接一条容量为无穷大,费用为Cij的有向边。
求最小费用最大流,最小费用流值就是最少运费,求最大费用最大流,最大费用流值就是最多运费。
【建模分析】
二分图最佳匹配建模方法为费用流模型。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define INF 1<<30
#define maxN 2000
#define maxE 100000
struct Edge{
int u,v,w,c,next;
};
Edge edge[maxE];
int cnt=0;
int head[maxN],pre[maxN],d[maxN];
bool vis[maxN];
int q[1000000];
int s,t;
int n;
int cost[maxN][maxN];
void addedge(int u,int v,int w,int c){
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].c=c;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].u=v;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].c=-c;
edge[cnt].next=head[v];
head[v]=cnt++;
}
bool MINSPFA(){
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(int i=s;i<=t;i++) d[i]=INF;
vis[s]=1;
int l=0,r=0;
q[r++]=s;
d[s]=0;
while(l<r){
int u=q[l++];
vis[u]=0;
for(int j=head[u];j!=-1;j=edge[j].next){
int v=edge[j].v;
if(edge[j].w>0 && edge[j].c+d[u]<d[v]){
d[v]=d[u]+edge[j].c;
pre[v]=j;
if(!vis[v]){
vis[v]=1;
q[r++]=v;
}
}
}
}
if(d[t]==INF) return false;
else return true;
}
bool MAXSPFA(){
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(int i=s;i<=t;i++) d[i]=-INF;
vis[s]=1;
int l=0,r=0;
q[r++]=s;
d[s]=0;
while(l<r){
int u=q[l++];
vis[u]=0;
for(int j=head[u];j!=-1;j=edge[j].next){
int v=edge[j].v;
if(edge[j].w>0 && edge[j].c+d[u]>d[v]){
d[v]=d[u]+edge[j].c;
pre[v]=j;
if(!vis[v]){
vis[v]=1;
q[r++]=v;
}
}
}
}
if(d[t]==-INF) return false;
else return true;
}
int MINMCMF(){
int sum=0;
while(MINSPFA()){
int aug=INF;
int u;
u=t;
while(u!=s){
if(aug>edge[pre[u]].w) aug=edge[pre[u]].w;
u=edge[pre[u]].u;
}
u=t;
while(u!=s){
edge[pre[u]].w-=aug;
edge[pre[u]^1].w+=aug;
u=edge[pre[u]].u;
}
sum+=d[t]*aug;
}
return sum;
}
int MAXMCMF(){
int sum=0;
while(MAXSPFA()){
int aug=INF;
int u;
u=t;
while(u!=s){
if(aug>edge[pre[u]].w) aug=edge[pre[u]].w;
u=edge[pre[u]].u;
}
u=t;
while(u!=s){
edge[pre[u]].w-=aug;
edge[pre[u]^1].w+=aug;
u=edge[pre[u]].u;
}
sum+=d[t]*aug;
}
return sum;
}
int main(){
//freopen("match.txt","r",stdin);
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&cost[i][j]);
memset(head,-1,sizeof(head));
cnt=0;
s=0; t=2*n+1;
for(i=1;i<=n;i++) addedge(s,i,1,0);
for(i=1;i<=n;i++) addedge(i+n,t,1,0);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
addedge(i,n+j,INF,cost[i][j]);
printf("%d\n",MINMCMF());
memset(head,-1,sizeof(head));
cnt=0;
for(i=1;i<=n;i++) addedge(s,i,1,0);
for(i=1;i<=n;i++) addedge(i+n,t,1,0);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
addedge(i,n+j,INF,cost[i][j]);
printf("%d\n",MAXMCMF());
return 0;
}