【休闲杯】AK大派送水题赛 题解

本文深入探讨了编程领域的六个关键部分,包括大数据开发、开发工具、嵌入式硬件、音视频基础、AI音视频处理和文档协作与知识管理。通过详细解析每个领域的主要技术和应用,为读者提供了一次全面的技术之旅。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一题:

第一题很简单,直接在输入之后,布尔类型数组相应的区域覆盖就可以了。

#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值