zoukankan      html  css  js  c++  java
  • ZROI week1

    \[ZROI day1 \]

    $$Grid$$

    • 题目描述
      给定一个矩阵,小写字母,求一条路径使得从\((1,1) -> (n,m)\),字典序最小,并且每次只能向右或者向下。

    • 题解

    先考虑如果没有重复字母,可以再\(dfs\)的过程中不断贪心得到路径。

    如果有重复的话,考虑枚举每条对角线,求出到这条对角线的最小字典序路径和所有可能的结束位置。

    复杂度\(O(n \times m)\)

    还有一种就是考虑预处理出每一步最接近答案的最远点,进行bfs即可。

    ps:忘记\(unique\),考试的时候T1调了一个半小时多。。。

    $$water$$

    • 题目描述

    • 题解
      裸状压dp题。

    ps:这题打挂了就20分

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 30;
    const int INF = (1 << 30) - 1;
    int c[MAXN][MAXN];
    #define rep(i,_,__)for(int i = _;i <= __; ++i)
    #define down(i,_,__) for(int i = _;i >= __; --i)
    const int U = 1 << 21;
    
    
    int f[U];
    int Count(int state) {
    	bitset <100> bit;
    	bit = state;
    	return bit.count();
    }
    
    int n;
    int k;
    #define all (1 << n)
    int ans = INF;
    int main () {
    	cin >> n >> k;
    	rep(i,0,n - 1) {
    		rep(j,0,n - 1) {
    			cin >> c[i][j];
    		}
    	}
    	for(int i = 0;i <= all; ++i) f[i] = INF;
    	f[all - 1] = 0;
    	down(state,all - 1,0) {
    		//cout<<Count(state)<<endl;
    		rep(i,0,n - 1) {
    			if(state & (1 << i)) {
    				rep(j,0,n - 1) {
    					if(i == j) continue;
    					f[(state - (1 << i)) | (1 << j)] = min(f[(state - (1 << i)) | (1 << j)],f[state] + c[i][j]);
    				}
    			}
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    $$pal$$

    • 题目描述
      给定一个序列,每次可以合并相邻的数字,合并之后是一个新数等于原数之和,求最少合并次数使得变成一个回文序列。

    • 题解
      指针扫描即可。

    证明:
    给定序列:1 5 3 2 1
    考虑分治这个过程,第一个和最后一个相等,那么这个东西就永远不能动,否则会增加次数,如果相等把指针l ++,r --,如果不一样找到小的往前合并,直到相等,类似解子问题的思路。

    ps:一眼+5min证明

    $$LIS$$

    • 题目描述
      按照一定规则构造序列,求构造出的所有序列中LIS长度和数目。

    • ps:先来ps一下,想出来了没时间写,中途去干了某些事情QAQ

    • 题解
      长度好说,贪心构造就行。
      怎么算方案数?
      经典计数问题,设\(f_i\)表示以\(i\)结尾的LIS长度,\(g_i\)表示\(f_i\)的方案数
      略写转移即可,虽然比较难写。

    \[作业 \]

    $$T1 : poj 2411$$

    记录放的状况转移即可。

    #include <cstdio>
    using namespace std;
    #define ll long long
    const int MAXN = 12;
    ll f[MAXN][1 << MAXN];
    bool state[1 << MAXN];
    #define U 1 << m
    int n,m;
    int main () {
    	while(~scanf("%d %d",&n,&m)) {
    		if(!n and !m) return 0;
    		for(int i = 0;i < U; ++i) {
    			bool odd = 0;
    			bool stp = 0;
    			for(int j = 0;j < m; ++j) {
    				if(i >> j & 1) {
    					odd |= stp;
    					stp = 0;
    				}
    				else stp ^= 1;
    			}
    			state[i] = odd | stp ? 0 : 1;
    		}
    		f[0][0] = 1;
    		for(int i = 1;i <= n; ++i) {
    			for(int j = 0;j < U; ++j) {
    				f[i][j] = 0;
    				for(int k = 0;k < U; ++k) {
    					if((j & k) == 0 and state[j | k]) {
    						f[i][j] += f[i - 1][k];
    					}
    				}
    			}
    		}
    		printf("%lld\n",f[n][0]);
    	}
    	return 0;
    }
    

    $$T2 : hdu 6006$$

    枚举每个工程师的情况,做背包即可。

    调了半天...

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int MAXN = 20;
    #define ll long long
    #define C continue
    ll f[MAXN][1 << 11];
    vector<int>v[MAXN],a[MAXN],b[MAXN];
    
    int vis[300];
    void Clear() {
    	memset(f,0,sizeof f);
    	memset(vis,0,sizeof vis);
    	for(int i = 0;i < 20; ++i) {
    		v[i].clear();
    		a[i].clear();
    		b[i].clear();
    	}
    }
    #define pb(x) push_back(x)
    int n,T,m;
    int read () {
    	int q=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')f=-1;ch=getchar();
    	}
    	while(isdigit(ch)) {
    		q=q*10+ch-'0';ch=getchar();
    	}
    	return q*f;
    }
    int cas;
    int main () {
    	T = read();
    	while(T--) {
    		Clear();
    		n = read(),m = read();
    		for(int i = 1;i <= n; ++i) {
    			int num = read();
    			for(int j = 1;j <= num; ++j) {
    				a[i].pb(read());
    			}
    		}
    		for(int i = 1;i <= m; ++i) {
    			int num = read();
    			for(int j = 1;j <= num; ++j) {
    				b[i].pb(read());
    			}
    		}
    		for(int i = 1;i <= n; ++i) {
    			for(int j = 0;j < (1 << m); ++j) {
    				memset(vis,0,sizeof vis);
    				int cnt = 0;
    				for(int k = 0;k < m; ++k) {
    					if(j & (1 << k)) {
    						cnt ++;
    						for(int l = 0;l < b[k + 1].size(); ++l) {
    							vis[b[k + 1][l]] ++;
    						}
    					}
    				}
    				if(cnt > 3) C;
    				bool tag = 1;
    				for(int k = 0;k < a[i].size(); ++k) {
    					if(vis[a[i][k]] == 0) {
    						tag = 0;
    					}
    				}
    				if(tag == 1) v[i].pb(j);
    			}
    		}
    		for(int state = 0;state < (1 << m); ++state) {
    			for(int j = 0;j < v[1].size(); ++j) {
    				if((state | v[1][j]) == state) {
    					f[1][state] = 1;
    				}
    			}
    		}
    		for(int i = 2;i <= n; ++i) {
    			for(int state = 0 ;state < (1 << m); ++ state) {
    				for(int j = 0;j < v[i].size(); ++j) {
    					if((state | v[i][j]) == state) {
    						f[i][state] = max(f[i][state],f[i - 1][state - v[i][j]] + 1);
    					}
    				}
    				f[i][state] = max(f[i][state],f[i - 1][state]);
    			}
    		}
    		printf("Case #%d: %lld\n",++cas, f[n][(1 << m) - 1]);
    	}
    	return 0;
    }
    

    $$T3 : hdu 4640$$

    考虑把每个人移动的状态压成二进制,dp即可。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int MAXN = 21;
    const int U = (1 << 18);
    const int INF = 0x3f3f3f3f;
    int T;
    int x,y,z;
    typedef pair<int,int> P;
    int a[MAXN][MAXN];
    int sum;
    int n,m;
    int ans;
    int Q;
    int f[U][MAXN];
    int g[4][U];
    int vis[U][MAXN];
    queue<P>q;
    int cas;
    #define mk(x,y) make_pair(x,y)
    #define fir first
    #define sec second
    void bfs() {
    	q.push(mk(0,0));
    	memset(vis,0,sizeof vis);
    	for(int i = 0;i < (1 << n); ++i) {
    		for(int j = 0;j < n; ++j) {
    			f[i][j] = INF;
    		}
    	}
    	f[0][0] = 0;
    	while(!q.empty()) {
    		P now = q.front();
    		q.pop();
    		int start = now.fir;
    		int end = now.sec;
    		vis[start][end] = 0;
    		for(int i = 0;i < n; ++i) {
    			if(a[end][i] < INF && f[start | (1 << i)][i] > f[start][end] + a[end][i]) {
    				f[start | (1 << i)][i] =f[start][end] + a[end][i];
    				if(vis[start | (1 << i)][i] == 0) {
    					vis[start | (1 << i)][i] = 1;
    					q.push(mk(start | (1 << i),i));
    				}
    			}
    		}
    	}
    }
    
    int main () {
    	cin >> T;
    	while(T--) {
    		cin >> n >> m;
    		for(int i = 0;i <= n; ++i) {
    			for(int j = 0;j <= n; ++j) {
    				a[i][j] = INF;
    				if(i == j) a[i][j] = 0;
    			}
    		}
    		for(int i = 1;i <= m; ++i) {
    			cin >> x >> y >> z;
    			-- x;
    			-- y;
    			a[x][y] = a[y][x] =min(a[x][y],z);
    		}
    		sum = 0;
    		cin >> Q;
    		while(Q--) {
    			int state;
    			cin >> state;
    			sum |= (1 << (state - 1));
    		}
    		bfs();
    		printf("Case %d: ",++cas);
    		for(int i = 1;i <= 3; ++i) {
    			for(int j = 0;j < (1 << n); ++j) {
    				g[i][j] = INF;
    			}
    		}
    		for(int i = 0;i < (1 << n); ++i) {
    			for(int j = 0;j <n; ++j) {
    				g[1][i] = min(g[1][i],f[i][j]);
    			}
    		}
    		for(int i = 2;i <= 3; ++i) {
    			for(int j = 0;j < (1 << n); ++j) {
    				for(int k = j; k ;k = (k - 1) & j) {
    					g[i][j] = min(g[i][j],max(g[1][k],g[i - 1][j ^ k]));
    				}
    			}
    		}
    		ans = INF;
    		for(int i = 1;i <= 3; ++i) {
    			for(int j = 0;j < (1 << n); ++j) {
    				if((sum & j) == sum) {
    					ans = min(ans,g[i][j]);
    				}
    			}
    		}
    		if(ans == INF) {
    			puts("-1");
    		}
    		else cout<<ans<<endl;
    	}
    	return 0;
    }
    

    $$T4 : hdu 4462$$

    枚举每个合法状态,暴力即可。

    ps:hdu居然不认and操作

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <bitset>
    #define C continue
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int MAXN = 51;
    const int MAXM = 11;
    bitset<3000>bit[MAXM],state;
    struct position {
    	int x;
    	int y;
    }p[MAXN << 1];
    bool find(int x,int y,int z) {
    	return x + y <= z;
    }
    int n,k;
    int ans;
    int Range[MAXN * MAXN];
    int vis[MAXN][MAXN];
    int x,y;
    int main () {
    	while(cin >> n && n) {
    		cin >> k;
    		memset(vis,0,sizeof vis);
    		for(int i = 1;i <= k; ++i) {
    			cin >> x >> y;
    			p[i].x = x;
    			p[i].y = y;
    			vis[p[i].x][p[i].y] = 1;
    		}
    		for(int i = 1;i <= k; ++i) {
    			cin >> Range[i];
    		}
    		for(int i = 1;i <= k; ++i) {
    			bit[i].reset();
    			for(int j = 1;j <= n; ++j) {
    				for(int k = 1;k <= n; ++k) {
    					if(vis[j][k]) {
    						C;
    					}
    					if(find(abs(j - p[i].x),abs(k - p[i].y),Range[i])) {
    						bit[i].set((j - 1) * n + k - 1);
    					}
    				}
    			}
    		}
    		ans = INF;
    		for(int i = 0;i < (1 << k); ++i) {
    			int cnt = 0;
    			state.reset();
    			for(int j = 1;j <= k; ++j) {
    				if(i & (1 << (j - 1))) {
    					cnt ++;
    					state |= bit[j];
    				}
    			}
    			if(state.count() == n * n - k) {
    				ans = min(ans,cnt);
    			}
    		}
    		if(ans == INF) {
    			cout<<-1<<endl;
    		}
    		else cout<<ans<<endl;
    	}
    }
    

    $$T5 : hdu 3017$$

    考虑是\(^{30}\),我们用双向搜索,每次让两个方向的搜索选一个状态,最后拼起来判断即可。
    (基本套路)

    finished

  • 相关阅读:
    循序渐进学习XHTML
    一些常用正则表达式
    输入框限制
    Oracle 取随机数
    安装部署中的数据库打包和快捷方式启动浏览器
    游标小例
    查询列数
    临时表简介
    Update动态更新
    sql 多列转一列
  • 原文地址:https://www.cnblogs.com/akoasm/p/10126491.html
Copyright © 2011-2022 走看看