第三次CCF计算机软件能力认证

题目感受:
T5 的最小费用流不会,学了几天只是勉强听懂了的程度
综合前几套来看,不熟练 完全不会 的知识点有:状压DP、费用流

201412-1 门禁系统

简单题,直接放代码:

#include <cstdio>
#include <iostream>
using namespace std;
const int maxn=1e3+5;

int n,x,a[maxn]; 

int main()
{
	for(cin>>n;n;n--){
		cin>>x;
		cout<<++a[x]<<' ';
	}
	return 0;
}

201412-2 Z字形扫描

模拟题,没啥技巧可言,直接给出代码:

#include <cstdio>
#include <iostream>
using namespace std;
const int maxn=505;

int n,a[maxn][maxn];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>a[i][j];
	int x=1,y=1;
	bool run=false,dir=false;
	cout<<a[x][y]<<' ';
	while(x<n||y<n){
		if(run){
			do{
				if(dir) cout<<a[++x][--y]<<' ';
				else cout<<a[--x][++y]<<' ';
			}while(1<x&&x<n&&1<y&&y<n);
			run=false;			
		}
		else{
			if(x==1){
				if(y<n) cout<<a[x][++y]<<' ';
				else cout<<a[++x][y]<<' ';
			}
			else if(y==1){
				if(x<n) cout<<a[++x][y]<<' ';
				else cout<<a[x][++y]<<' ';
			}
			else if(x==n){
				cout<<a[x][++y]<<' '; 
			}
			else if(y==n){
				cout<<a[++x][y]<<' ';
			}
			run=true;
			dir=!dir;	
		}
	}
	return 0;
}

201412-3 集合竞价

这道题目数据范围很小,直接枚举就能过;
我用的是 复杂度更优的做法,即前缀和+双指针,相应的,代码也就更长。
P.S. 这种反复对vector进行各种操作,思路简单但步骤繁琐让人感觉像是在做 codeforces 的题目 …
代码:

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<db,int> P;
const int maxn=5e3+5;

P buy[maxn],sell[maxn];
ll bsum[maxn],ssum[maxn];

struct Record{
	bool typ; db price; int num;
}in[maxn];

int main()
{
	string s,type;
	int id,tot=0;
	while(cin>>type){
		tot++;
		if(type=="buy"){
			in[tot].typ=0;
			cin>>in[tot].price>>in[tot].num;
		}
		else if(type=="sell"){
			in[tot].typ=1;
			cin>>in[tot].price>>in[tot].num;
		}
		else{
			cin>>id;
			in[id].num=-1;
		}
	}
	
	int scnt=0,bcnt=0;
	for(int i=1;i<=tot;i++){
		if(in[i].num==-1||in[i].num==0) continue;
		if(in[i].typ){
			scnt++;
			sell[scnt].first=in[i].price;
			sell[scnt].second=in[i].num;
		}
		else{
			bcnt++;
			buy[bcnt].first=in[i].price;
			buy[bcnt].second=in[i].num;
		}
	}
	sort(sell+1,sell+scnt+1);
	sort(buy+1,buy+bcnt+1);
	for(int i=1;i<=scnt;i++) ssum[i]=ssum[i-1]+sell[i].second;
	for(int i=1;i<=bcnt;i++) bsum[i]=bsum[i-1]+buy[i].second;
	
	db pri=0;
	ll ans=0;
	int idx=1;
	for(int i=1;i<=bcnt;i++){
		db p=buy[i].first;
		while(idx<=scnt&&sell[idx].first<=p) idx++;		
		if(min(ssum[idx-1], bsum[bcnt]-bsum[i-1])>=ans){
			pri=p;
			ans=min(ssum[idx-1], bsum[bcnt]-bsum[i-1]);			
		}
	}
	printf("%.2f %lld\n",pri,ans);
	return 0;
}

201412-4 最优灌溉

最小生成树裸题,直接 Kruskal:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=1e3+5;
const int maxm=1e5+5;

struct Edge{ int from,to,w; }e[maxm];
bool cmp(Edge e1,Edge e2){
	return e1.w<e2.w;
} 

int n,m,fa[maxn];

int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}

int main()
{
	cin>>n>>m;
	for(int i=0;i<m;i++)
		cin>>e[i].from>>e[i].to>>e[i].w;
	sort(e,e+m,cmp);
	for(int i=1;i<=n;i++) fa[i]=i;
	ll ans=0;
	for(int i=0;i<m;i++){
		int u=e[i].from, v=e[i].to;
		u=find(u),v=find(v);
		if(u==v) continue;
		else{
			ans+=e[i].w;
			fa[u]=v;
		}
	}
	cout<<ans<<'\n';
	return 0;
}

201412-5 货物调度

费用流题目
没学过做不出来,直接看了yxc的录播学会了怎么建图,又找了几个比较好的网络流视频,熟悉了一些基础知识,这里mark一下:
算法进阶课(试听课)—— 网络流的基本概念
[算法竞赛入门] 网络流基础:理解最大流/最小割定理 (蒋炎岩)
代码:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=705; // 100 * 7
const int maxm=(maxn*3 + 500*7*2) * 2;

int n,m,S,T;
struct Edge{ int to,cap,w,next; }e[maxm];
int head[maxn],idx;
int d[maxn],pre[maxn],incf[maxn]; // pre数组存储每个点在最短路上前一条边的编号; incf数组代表每个点的流量 
bool vis[maxn]; // 用于spfa中判断是否在队列中 

//a号点在第b天的编号 
inline int get(int a,int b){
	if(b==8) b=1;
	return (a-1)*7+b;
}

// 建立一条a到b容量是c费用是d的边 
void add(int a,int b,int c,int d){
	e[idx].to=b, e[idx].cap=c, e[idx].w=d, e[idx].next=head[a], head[a]=idx++;
	e[idx].to=a, e[idx].cap=0, e[idx].w=-d, e[idx].next=head[b], head[b]=idx++;
}

bool spfa(){
	memset(d,0x3f,sizeof d); // 初始化每个点的距离 
	memset(incf,0,sizeof incf); // 初始化每个点的流量
	memset(vis,0,sizeof vis);
	queue<int> Q;
	Q.push(S), d[S]=0, incf[S]=INF;
	while(!Q.empty()){
		int t=Q.front();
		Q.pop();
		vis[t]=false;
		
		for(int i=head[t];~i;i=e[i].next){
			int ver=e[i].to;
			if(e[i].cap>0 && d[ver]>d[t]+e[i].w){
				d[ver]=d[t]+e[i].w;			
				pre[ver]=i;
				incf[ver]=min(incf[t], e[i].cap);
				if(!vis[ver]){
					Q.push(ver);
					vis[ver]=true;
				}
			}
		}
	}
	return incf[T]>0;	
}

void EK(int& flow, int& cost){
	flow=cost=0;
	while(spfa()){
		int t=incf[T];
		flow+=t,cost+=t*d[T];
		for(int i=T;i!=S;i=e[pre[i]^1].to){
			e[pre[i]].cap-=t;
			e[pre[i]^1].cap+=t;
		}
	}
}

int main()
{
	cin>>n>>m;
	S=0, T=7*n+1;
	memset(head, -1, sizeof head);
	for(int i=1;i<=n;i++){
		int cap,cost;
		for(int j=1;j<=7;j++){
			cin>>cap;
			add(S,get(i,j),cap,0);
		}
		for(int j=1;j<=7;j++){
			cin>>cap;
			add(get(i,j),T,cap,0);
		}
		cin>>cap>>cost;
		for(int j=1;j<=7;j++)
			add(get(i,j), get(i,j+1), cap, cost); 
	}
	while(m--){
		int u,v,cost;
		cin>>u>>v>>cost;
		for(int i=1;i<=7;i++){
			add(get(u,i),get(v,i),INF,cost);
			add(get(v,i),get(u,i),INF,cost);
		}
	}	
	int flow,cost;
	EK(flow,cost);
	cout<<cost<<'\n';
	return 0;
}

总的来说Dinic算法还没学,而且基EK算法的网络流发展而来的费用流算法也没有学的很明白,感觉要完全掌握基础部分,达到独立切模板题还需要时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值