【NOIP2018模拟赛2018.10.27】

小猫爬山

【题目描述】:

Freda和rainbow饲养了N只小猫,这天,小猫们要去爬山。经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。

Freda和rainbow只好花钱让它们坐索道下山。索道上的缆车最大承重量为W,而N只小猫的重量分别是C1、C2……CN。当然,每辆缆车上的小猫的重量之和不能超过W。每租用一辆缆车,Freda和rainbow就要付1美元,所以他们想知道,最少需要付多少美元才能把这N只小猫都运送下山?

【输入描述】:

第一行包含两个用空格隔开的整数,N和W。

接下来N行每行一个整数,其中第i+1行的整数表示第i只小猫的重量Ci。

【输出描述】:

输出一个整数,最少需要多少美元,也就是最少需要多少辆缆车。

【样例输入】:

5 1996
1
2
1994
12
29

【样例输出】:

2

【时间限制、数据范围及描述】:

时间:1s 空间:128M

对于100%的数据,1<=N<=18,1<=Ci<=W<=10^8。

题意就是有n只猫,分别重wi,然后要装进若干个承重为w的缆车里,问最少用的缆车数。

正解应该是迭代加深深搜,但是lz贪心直接水过100分。。。

深搜不说了,贪心就是尽量让体重最小的跟体重最大的坐在一起,能装就装。(感觉一般现实生活中我们也会这样处理这种问题吧,但是前辈们说这种贪心不对,但我觉得没有更优地做法了呀。。望知道的dalao告诉蒟蒻qwq)

代码5分钟写出来:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define gc getchar
#define ex pt('\n')
#define ko pt(' ')
const int MAXN = 20;
int n,w;
int v[MAXN],vis[MAXN]; 
int ans = 0;
void in(int &x)
{
	int num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}

int main()
{
	in(n); in(w);
	for(int i = 1;i <= n;i++) in(v[i]);
	sort(v+1,v+1+n);
	for(int i = 1;i <= n;i++)
	{
		if(vis[i]) continue;
		ans++;
		int now = v[i]; vis[i] = 1;
		for(int j = n;j >= i;j--)
			if(now + v[j] <= w && !vis[j]) 
				vis[j] = 1,now += v[j];
	}
	out(ans);
	return 0;
}

得分

这道题老师没放出来题目orz

大概题意是:一位同学要在T时间内做n道题中的全部或是部分,每道题有一个题目难度ci,需要时间ti,在剩余时间x时开始做第i道题并且能做完的话,就可以得到x*ci的分,问可以得到的最大得分。

很明显是个01背包问题,但是要注意的是dp顺序必须按 性价比(ci/ti :cj/tj) 从大到小来进行,不然答案无法被正确更新(至于为什么,我也不是很明白,但是经过模拟发现若顺序不对,就会导致答案没有被更新出来,似乎是被前面的不优的东西挤掉了空间)

因为除法很麻烦,还要处理浮点数,所以比较函数写成 ci*tj > cj*ti  就好。

哦对了,我的方程意思是f[j]代表当前剩余时间,最后答案明显取个最大(也许就是f[0]?),由于是01背包只能限制f从上一阶段逆向枚举过来,保证只转移一次。

但是呀我这里方程意思是剩余时间,那么相对于背包装进j来说的逆向是从已经装了m进行逆向枚举转移,同时可以想到对于剩余时间来说,就应该从0开始转移到m才算是逆向,故方程如下代码。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define gc getchar
#define ex pt('\n')
#define ko pt(' ')
const int MAXN = 3e3 + 5;
int n,m;
struct score
{
	int t,c;
	bool operator < (const score &one) const
	{
		return c*one.t > one.c*t;
	}
}s[MAXN];
int f[10005];
int ans = 0;
void in(int &x)
{
	int num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}

int main()
{
	in(n); in(m);
	for(int i = 1;i <= n;i++) in(s[i].t),in(s[i].c);
	sort(s+1,s+1+n);
	for(int i = 1;i <= n;i++)
		for(int j = s[i].t;j <= m;j++)
			f[j-s[i].t] = max(f[j-s[i].t],f[j] + j*s[i].c);
	for(int i = 0;i <= m;i++) ans = max(ans,f[i]);
	out(ans);
	return 0;
}

迷路

Description
windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

Input
第一行包含两个整数,N T。 接下来有 N 行,每行一个长度为 N 的字符串。 第i行第j列为'0'表示从节点i到节点j没有边。 为'1'到'9'表示从节点i到节点j需要耗费的时间。

Output
包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。

Sample Input
【输入样例一】
2 2
11
00

【输入样例二】
5 30
12045
07105
47805
12024
12345


Sample Output
【输出样例一】
1

【样例解释一】
0->0->1

【输出样例二】
852

HINT
30%的数据,满足 2 <= N <= 5 ; 1 <= T <= 30 。 100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
这道题爆零了orz。。一般来说都会想到处理环(包括自环)吧。。于是打了个tarjan缩点,dfs求最短路,最后利用缩点得来的每个环路径长短,进行拼凑T。失败了orzorzorz,居然全错。。

正解为矩阵乘法快速幂,可以知道这个图本身就是一个矩阵,要是要走T次到达终点的话相当于每次自乘矩阵,每一条边都是一种选择的情况,先按矩阵乘法乘,那个加起来的值就是从一个点到另一个点的情况和。起点到终点答案就是f[1][n]。

但是这种情况只能处理每条边边权均为1的情况,若大于1则不能这么处理了。

于是我们发现边权只有0~9,0,1不需要考虑,2~9边权的话就把一个点拆成2~9个点相连的边权为1的边,加在矩阵后面就好了,答案还是f[1][n]处取得。

计算怎么加在后面详细看代码就好了,就是那个calc函数。。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define gc getchar
#define ko pt(' ')
#define ex pt('\n')
const int MAXN = 150;
const ll MOD = 2009;
int n,m,sum,T;
int ans[MAXN][MAXN],a[MAXN][MAXN],b[MAXN][MAXN];

inline int calc(int x,int y) {return (y-1)*n+x;}

void in(int &x)
{
	int num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void lin(ll &x)
{
	ll num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void out(ll x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}

inline void mul()
{
	memset(b,0,sizeof b);
	for(int i = 1;i <= n*9;i++)
		for(int j = 1;j <= n*9;j++)
			for(int k = 1;k <= n*9;k++)
				b[i][j] = (b[i][j] + ans[i][k]*a[k][j]) % MOD;
	memcpy(ans,b,sizeof b);
}

inline void mulself()
{
	memset(b,0,sizeof b);
	for(int i = 1;i <= n*9;i++)
		for(int j = 1;j <= n*9;j++)
			for(int k = 1;k <= n*9;k++)
				b[i][j] = (b[i][j] + a[i][k]*a[k][j]) % MOD;
	memcpy(a,b,sizeof b);
}

inline void init()
{
	in(n); in(T);
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= n;j++)
		{
			char ch = getchar();
			int num = ch-'0';
			if(!num) continue;
			a[i][calc(j,num)] = 1;
		}
		for(int j = 2;j <= 9;j++) a[calc(i,j)][calc(i,j-1)] = 1;
		getchar();
	}
}

inline void work()
{
	for(int i = 1;i <= n*9;i++) ans[i][i] = 1;
	while(T)
	{
		if(T & 1) mul();
		T >>= 1;
		mulself();
	}
	out(ans[1][n] % MOD);
}

int main()
{
	init();
	work();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/chang_yl/article/details/83474473