小猫爬山
【题目描述】:
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;
}