每天一套题打卡|河南省第七届ACM/ICPC
A 海岛争霸
题目:Q次询问,他想知道从岛屿A 到岛屿B 有没有行驶航线,若有的话,所经过的航线,危险程度最小可能是多少。
多源点最短路,用floyd
在松弛更新:g[i][k] < g[i][j] && g[k][j] < g[i][j]时,g[i][j] = max(g[i][k],g[k][j]);
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;
int n,m;
int q;
int g[maxn][maxn];
const int inf = 0x3f3f3f3f;
// 初始化 g 矩阵
void init() {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (i == j) {
g[i][j] = 0;
} else {
g[i][j] = inf;
}
}
}
}
// 插入一条带权有向边
void insert(int u, int v, int w) {
g[u][v] = w;
}
// 核心代码
void floyd() {
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
//这里是本题的核心 松弛更新
if(g[i][k] < g[i][j] && g[k][j] < g[i][j]){
g[i][j] = max(g[i][k],g[k][j]);
}
}
}
}
}
int main(){
cin>>n>>m;
init();
for(int i=1;i<=m;i++){
int a,b,v;
cin>>a>>b>>v;
if(v < g[a][b]){
insert(a,b,v);
insert(b,a,v);
}
}
floyd();
cin>>q;
while(q--){
int a,b;
cin>>a>>b;
if(g[a][b] == inf){
cout<<-1<<endl;
}else{
cout<<g[a][b]<<endl;
}
}
return 0;
}
*B 物资调度
1.dfs剪枝都能过。。
2.dp当然也可以,0-1背包
3.二进制枚举wa了
#include<bits/stdc++.h>
using namespace std;
//AC
const int maxn = 110;
int t;
int n,m;
int a[maxn];
int vis[maxn];
int ans = 0;
//第k个数 当前值为sum
void dfs(int k,int sum){
if(sum > m) return;
if(k==n+1){
if(sum == m){
ans++;
}
return;
}
//每个数有两种选择:用这个数 和 不用这个数 都dfs搜索一遍
dfs(k+1,sum);//不用这个数
if(sum + a[k]<=m){
dfs(k+1,sum+a[k]);//用这个数 sum就需要加上当前这个数的值
}
}
int main(){
cin>>t;
while(t--){
ans = 0;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
memset(vis,0,sizeof(vis));
dfs(1,0);
cout<<ans<<endl;
}
return 0;
}
二进制枚举做法
#include<bits/stdc++.h>
using namespace std;
//WA
const int maxn = 110;
int t;
int n,m;
int a[maxn];
int main(){
cin>>t;
while(t--){
int ans = 0;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
//枚举0 ~ 1<<n种状态
for(int i=0; i<(1<<n); i++){
int sum = 0;
for(int j=1;j<=n;j++){
if(i & (1<<(j-1))){
sum += a[j];
}
}
if(sum == m){
// cout<<i<<endl;
ans++;
}
}
cout<<ans<<endl;
}
return 0;
}
*D 山区修路
我只能写个2次dp的 暴力解法,但是这里ai 有1e9这么大,wa。
再补题。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;
int t;
int n;
int dp[maxn][maxn][2];
int a[maxn];
const int inf = 0x3f3f3f3f;
int main(){
cin>>t;
while(t--){
cin>>n;
int maxh = 0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i] > maxh) maxh = a[i];
}
memset(dp,inf,sizeof(dp));
for(int i=0;i<=maxh;i++){
dp[1][i][0] = abs(a[1] - i);
dp[1][i][1] = abs(a[1] - i);
}
//从前推 低->高
for(int i=2;i<=n;i++){
for(int j=0;j<=maxh;j++){
for(int k=0;k<=j;k++){
dp[i][j][0] = min(dp[i][j][0],dp[i-1][k][0] + abs(a[i] - j));
}
}
}
//从前推 高->低
for(int i=2;i<=n;i++){
for(int j=0;j<=maxh;j++){
for(int k=j;k<=maxh;k++){
dp[i][j][1] = min(dp[i][j][1],dp[i-1][k][1] + abs(a[i] - j));
}
}
}
int ans = inf;
for(int i=0;i<=maxh;i++){
if(dp[n][i][1] < ans) ans = dp[n][i][1];
if(dp[n][i][0] < ans) ans = dp[n][i][0];
}
cout<<ans<<endl;
}
return 0;
}
F Turing equation
题意:看样例能猜到,the numbers being read backwards.
从后往前将字符串 转成三个数,判断和是否相等
#include<bits/stdc++.h>
using namespace std;
string s;
int main(){
while(cin>>s && !(s[0] == '0' && s[1] == '+' && s[2] == '0' && s[3] == '=' && s[4] == '0' )){
int len = s.length() - 1;
int c = 0;
int b = 0;
int a = 0;
int i = len;
while(i>=0 && s[i] == '0') i--;
while(i>=0 && s[i] >= '0' && s[i] <= '9'){
c = c*10 + (s[i]- '0');
i--;
if(s[i] == '=') break;
}
if(i>=0 && s[i] == '=') i--;
while(i>=0 && s[i] == '0') i--;
while(i>=0 && s[i] >= '0' && s[i] <= '9'){
b = b*10 + (s[i]- '0');
i--;
if(s[i] == '+') break;
}
if(i>=0 && s[i] == '+') i--;
while(i>=0 && s[i] == '0') i--;
while(i>=0 && s[i] >= '0' && s[i] <= '9'){
a = a*10 + (s[i]- '0');
i--;
}
if(a + b == c)
cout<<"TRUE"<<endl;
else
cout<<"FALSE"<<endl;
}
return 0;
}
H Rectangles
1.一眼递推
2.LIS的dp
题目英文,细节比较多
The list can be created from rectangles in any order and in either orientation. //长宽可以交换
A rectangle fits inside another rectangle if one of its sides is strictly smaller than the other rectangle's and the remaining side is no larger.//给了样例能懂
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
int t,n;
int a[maxn];
struct node{
int x;
int y;
};
//ac
bool cmp(const node &p,const node &q){
if(p.x == q.x) return p.y < q.y;
return p.x < q.x;
}
int main(){
cin>>t;
while(t--){
cin>>n;
node g[n+5];
for(int i=1;i<=n;i++){
int xi,yi;
cin>>xi>>yi;
if(xi < yi) swap(xi,yi); //这里是注意点
g[i].x = xi;
g[i].y = yi;
a[i] = 1;
}
sort(g+1,g+n+1,cmp); //排序
int ans = 1;
//递推
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if((g[j].x > g[i].x && g[j].y > g[i].y) || (g[j].x > g[i].x && g[j].y == g[i].y) || (g[j].x == g[i].x && g[j].y > g[i].y) ){
a[j] = max(a[j],a[i]+1);
}
}
}
for(int i=1;i<=n;i++){
if(a[i] > ans) ans = a[i];
}
cout<<ans<<endl;
}
return 0;
}
下面LIS最长上升子序列的写法,也AC的
#include<bits/stdc++.h>
using namespace std;
//ac
/*
A rectangle fits inside another rectangle if one of its sides is strictly smaller than the other rectangle's
and the remaining side is no larger.
If two rectangles are identical they are considered not to fit into each other.
For example, a 2*1 rectangle fits in a 2*2 rectangle, but not in another 2*1 rectangle.
容易看懂题意
*/
//The list can be created from rectangles in any order and in either orientation.
//意思是长宽可以交换 想法:那么我们在输入数据的时候把小的给长 大的给宽就可以了
const int maxn = 110;
int t,n;
int a[maxn];
struct node{
int x;
int y;
};
bool cmp(const node &p,const node &q){
if(p.x == q.x) return p.y < q.y;
return p.x < q.x;
}
int main(){
cin>>t;
while(t--){
cin>>n;
node g[n+5];
for(int i=1;i<=n;i++){
int xi,yi;
cin>>xi>>yi;
if(xi < yi) swap(xi,yi);
g[i].x = xi;
g[i].y = yi;
a[i] = 1;
}
sort(g+1,g+n+1,cmp);
int ans = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if((g[j].x < g[i].x && g[j].y < g[i].y) || (g[j].x < g[i].x && g[j].y == g[i].y) || (g[j].x == g[i].x && g[j].y < g[i].y) ){
a[i] = max(a[i],a[j]+1);
}
}
}
for(int i=1;i<=n;i++){
if(a[i] > ans) ans = a[i];
}
cout<<ans<<endl;
}
return 0;
}