文章目录
前言
白书中自我感觉学到了东西的题及题解,代码写的很棒,记录一下以便日后复习 ,持续更新中
1.Ants POJ - 1852 思维
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int x[1000001];
int main(){
int t,l,n;
scanf("%d",&t);
while(t--){
scanf("%d %d",&l,&n);
for(int i=0;i<n;i++)
scanf("%d",&x[i]);
int mint=0;
for(int i=0;i<n;i++)
mint = max(mint,min(x[i],l-x[i]));
int maxt = 0;
for(int i = 0;i < n;i++)
maxt = max(maxt,max(x[i],l-x[i]));
printf("%d %d\n",mint,maxt);
}
return 0;
}
2. Lake Counting POJ - 2386 深搜
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 110,MAX_M = 110;
int N,M;
char field[MAX_N][MAX_M + 1];
void dfs(int x,int y){
field[x][y] = '.';
for(int dx = -1;dx<=1;dx++){
for(int dy = -1;dy <=1 ;dy++){
int nx = x +dx,ny = y +dy;
if(nx>=0 && nx<N && ny>=0 && ny<M && field[nx][ny] == 'W')
dfs(nx,ny);
}
}
return ;
}
void solve(){
int res = 0;
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
if(field[i][j] == 'W'){
dfs(i,j);
res++;
}
}
}
printf("%d\n",res);
}
int main(){
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
scanf("%s",field[i]);
solve();
return 0;
}
3.Best Cow Line POJ - 3617 字符串问题
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 2e3+10;
int N;
char s[MAX_N + 1];
void solve(){
int count = 0;
int a = 0,b = N - 1;
while(a <= b){
bool left = false;
for(int i = 0; a + i <= b; i++){
if(s[a + i] <s[b - i]){
left = true;
break;
}
else if(s[a + i] > s[b - i]){
left = false;
break;
}
}
if(left)
putchar(s[a++]);
else
putchar(s[b--]);
count++;
if(count%80 == 0)
putchar('\n');
}
}
int main(){
scanf("%d",&N);
for(int i=0;i<N;i++)
getchar(),scanf("%c",&s[i]);
solve();
return 0;
}
4.Saruman’s Army POJ - 3069 贪心
AC代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX_N = 1e3+10;
int x[MAX_N];
int main()
{
int r,n,sum;
while(scanf("%d%d",&r,&n)&&(r!=-1||n!=-1)){
int i,k;
for(i=0;i<n;i++)
scanf("%d",&x[i]);
sort(x,x+n);
i=0,sum=0;
while(i<n){
int s=x[i++];
while(i<n && x[i]<=s+r) i++;
k=x[i-1];
while(i<n && x[i]<=k+r) i++;
sum++;
}
printf("%d\n",sum);
}
return 0;
}
5. Fence Repair POJ - 3253 思维/优先队列
AC代码:
//方案一 O(N^2)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX_N = 2e4+10;
int N,L[MAX_N];
void solve(){
ll ans = 0;
//直到计算到木板为1时为止
while(N>1){
//求出最短的板mii1和次短的板mii2
int mii1 = 0,mii2 = 1;
if(L[mii1] > L[mii2])
swap(mii1,mii2);
for(int i=2;i<N;i++){
if(L[i] < L[mii1]){
mii2 = mii1;
mii1 = i;
}
else if(L[i] < L[mii2])
mii2 = i;
}
//将两块板合并
int t = L[mii1] + L[mii2];
ans += t;
if(mii1 == N-1)
swap(mii1,mii2);
L[mii1] = t;
L[mii2] = L[N-1];
N--;
}
printf("%lld\n",ans);
}
int main(){
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d",&L[i]);
solve();
return 0;
}
//方案二O(NlogN)
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX_N = 2e4+10;
int N,L[MAX_N];
void solve(){
ll ans = 0;
//声明一个从小到大取出数值的优先队列
priority_queue<int,vector<int>,greater<int>>que;
for(int i=0;i < N;i++)
que.push(L[i]);
//循环到只剩一块木板为止
while(que.size() > 1){
//取出最短木板和次短的木板
int l1,l2;
l1 = que.top();
que.pop();
l2 = que.top();
que.pop();
//把两块木板合并
ans+=l1+l2;
que.push(l1+l2);
}
printf("%lld\n",ans);
}
int main(){
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d",&L[i]);
solve();
return 0;
}
6. Expedition POJ - 2431 优先队列
AC代码:
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 1e5;
int L,P,N;
struct xa{
int x;//距离终点城镇的距离
int dis;//距离起点卡车的距离
int oil;//加油站所含的油量
}st[MAX_N];
//输入无序,需要重排
bool cmp(xa v,xa u) {
return v.dis < u.dis;
}
void solve(){
//为了写起来方便,我们把终点也认为是加油站
st[N].dis = L;
st[N].oil = 0;
N++;
priority_queue<int> pque;
//ans:加油次数 pos:现在所在位置,tank:邮箱中汽油的量
int ans = 0,pos = 0,tank = P;
for(int i=0;i<N;i++){
//接下来要前进的距离
int d = st[i].dis - pos;
//不断加油直到油量足够行驶到下一个加油站
while(tank - d < 0){
if(pque.empty()){//如果在此之前的所有加油站的油都加上还是不能到达下一个加油站则 就不能到达终点
puts("-1");
return ;
}
tank += pque.top();//加上在此之前油量最多的加油站的油
pque.pop();
ans++;
}
tank -= d;//计算剩余油量
pos = st[i].dis;//记录现在所在位置
pque.push(st[i].oil);//把当前加油站的油加入队列
}
printf("%d\n",ans);
}
int main(){
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d %d",&st[i].x,&st[i].oil);
scanf("%d %d",&L,&P);
for(int i=0;i<N;i++)
st[i].dis = L-st[i].x;
sort(st,st+N,cmp);
solve();
return 0;
}
7.食物链 POJ - 1182 并查集
AC代码:
//方案一
#include<cstring>
#include<cstdio>
#define maxn 50005
using namespace std;
int f[maxn],n,k,d,x,y;
int r[maxn];//r[i]表示i与根节点的关系
//0-与父节点同类,1-被父节点吃,2-吃父节点
int getf(int x) {
if(x==f[x])
return x;
else {
int mid=f[x];
f[x]=getf(mid);//先递归这样是相当于一层一层推下来的
r[x]=(r[x]+r[mid])%3;//得出x与自己根节点的关系
return f[x];
}
}
void solve() {
int cnt=0;
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++) {
f[i]=i;
r[i]=0;
}
//初始化
while(k--) {
scanf("%d%d%d",&d,&x,&y);
if(x>n||y>n||(d==2&&x==y)) {
cnt++;
continue;
}
int xx=getf(x);
int yy=getf(y);
if(xx!=yy) {
f[yy]=xx;//把y的根节点(yy)连接到x的根节点(xx)上后,
r[yy]=(d-1+3-r[y]+r[x])%3;//(d-1)表示x与y的关系,此时y的根节点(yy)与根节点(xx)的关系
} else { //在同一棵树上
if(d==1&&r[x]!=r[y])//假话
cnt++;
if(d==2&&(3-r[x]+r[y])%3!=(d-1))//现在x应该吃y,d-1表示y->x
cnt++;
}
}
printf("%d\n",cnt);
}
int main() {
solve();
return 0;
}
详情博客
//方案二
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=50005;
int fa[maxn*3];
int n,m;
int ans;
int Find(int x){
int t=x;
while(fa[t]!=t) t=fa[t];
while(x!=t)
{
int temp=fa[x];
fa[x]=t;
x=temp;
}
return t;
}
void Join(int x,int y){
int fx=Find(x),fy=Find(y);
if(fx!=fy)
fa[fx]=fy;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=3*n;i++) fa[i]=i;
for(int i=1;i<=m;i++){
int num,a,b;
scanf("%d%d%d",&num,&a,&b);
if(a<1||a>n||b<1||b>n) {
ans++; continue;
}
if(num==2&&a==b){
ans++;continue;
}
if(num==1){//a,b同类
if(Find(a)==Find(b+n)||Find(b)==Find(a+n)) ans++;//如果a吃b或者b吃a,说明是假话
else {//否则是真话,建立a和b同类的关系
Join(a,b);
Join(a+n,b+n);
Join(a+2*n,b+2*n);
}
}
else if(num==2){//a吃b
if(Find(a)==Find(b)||Find(b)==Find(a+n)) ans++;//如果a,b同类或者b吃a,说明是假话
else {//否则是真话,建立a吃b的关系
Join(a,b+n);
Join(a+n,b+2*n);
Join(a+2*n,b);
}
}
}
printf("%d\n",ans);
return 0;
}
8.Roadblocks POJ - 3255 次短路
多理解一下
AC代码:
#include <iostream>
#include <vector>
#include <queue>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn=5005;
const int inf=1e9;
int N,R;
struct edge
{
int to,cost;
};
typedef pair<int ,int> P ;///first 是从1到second的最短路 second 是路口标号
vector<edge>G[maxn];///邻接表
int dist[maxn];///最短路
int dist2[maxn];///次短路
void solve()
{
priority_queue<P ,vector<P>,greater<P> >que;
fill(dist,dist+N,inf);
fill(dist2,dist2+N,inf);
dist[0]=0;
//dist2[0]=0;
que.push(P(0,0));
while(!que.empty()){
P p=que.top();//优先队列 ,用.top
que.pop();
int v=p.second ,d=p.first;
if(dist2[v]<d)continue;
for(int i=0; i<G[v].size(); i++){
edge e=G[v][i];
int d2=d+e.cost;
if(dist[e.to]>d2){
swap(dist[e.to],d2);
que.push(P(dist[e.to],e.to));
}
if(dist2[e.to]>d2&&dist[e.to]<d2){
dist2[e.to]=d2;
que.push(P(dist2[e.to],e.to));
}
}
}
printf("%d\n",dist2[N-1]);
}
int main()
{
int from;
while(cin>>N>>R)
{
edge now;
for(int i=0;i<R;i++)
{
cin>>from>>now.to>>now.cost;
from--;
now.to--;///标号从 0-N-1!!
G[from].push_back(now);
swap(now.to,from);
G[from].push_back(now);
}
solve();
}
return 0;
}
9.
一些细碎的知识
- memset()
memset是按照1字节为单位对内存进行填充,-1的每一位二进制位都是1,所以可以 像0,0x3f一样用memset进行初始化。通过使用memset可以快速的对高维数组等进行初始化,但是需要注意无法初始化成1之类的数值 - fill()
当我们想对一个容器的值进行填充时,我们就可以使用fill()函数。这里只说明一维数 组的填充
fill (array,array+4,5); // myvector: 5 5 5 5 0 0 0 0
fill (array+3,array+6,8); // myvector: 5 5 5 8 8 8 0 0
详情参考链接
快排模板
//模板一,一些大型数据可能会超时,不过一般情况下够用
#include <stdio.h>
int a[101],n;//定义全局变量,这两个变量需要在子函数中使用
void quicksort(int left, int right) {
int i, j, t, temp;
if(left > right)
return;
temp = a[left]; //temp中存的就是基准数
i = left;
j = right;
while(i != j) { //顺序很重要,要先从右边开始找
while(a[j] >= temp && i < j)
j--;
while(a[i] <= temp && i < j)//再找右边的
i++;
if(i < j)//交换两个数在数组中的位置
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//最终将基准数归位
a[left] = a[i];
a[i] = temp;
quicksort(left, i-1);//继续处理左边的,这里是一个递归的过程
quicksort(i+1, right);//继续处理右边的 ,这里是一个递归的过程
}
int main() {
int i;
//读入数据
scanf("%d", &n);
for(i = 1; i <= n; i++)
scanf("%d", &a[i]);
quicksort(1, n); //快速排序调用
//输出排序后的结果
for(i = 1; i < n; i++)
printf("%d ", a[i]);
printf("%d\n", a[n]);
return 0;
}
//模板二,相较模板一又有优化
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int n,a[N];
void quick_sort(int l,int r){
if(l >= r)
return ;
int x = a[(l+r+1)/2],i = l - 1,j = r + 1;
while(i < j){
do i++ ;while(a[i] < x);
do j-- ;while(a[j] > x);
if(i < j)
swap(a[i],a[j]);
}
quick_sort(l,i-1);
quick_sort(i,r);
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
quick_sort(0,n-1);
for(int i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
快读模板
inline int read() {
char c = getchar();
int x = 0, f = 1;
while (c < '0' || c > '9') {
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
快速幂模板
//求a^k的前三位和后三位
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll fast_power(ll base,ll power,ll mod){
ll result=1;
while(power>0){
if(power&1)
result=result*base%mod;
power>>=1;
base=(base*base)%mod;
}
return result;
}
int main(){
int t,v=1;
scanf("%d",&t);
while(t--){
ll n,k,x;
double ka,y,xy,j;
scanf("%lld %lld",&n,&k);
ka=k*log10(1.0*n);
x=(int)ka;
y=ka-x;
xy=pow(10,y)*100;
printf("Case %d: %d %03lld\n",v++,(int)xy,fast_power(n,k,1000));
//后三位用0补
}
return 0;
}
//求前三位:
//
//每一个数n都可以写作10^t(t大多是小数),则此时n^k可写作10^kt
//n=10^a
//n^k=10^ka
//ka=x+y(x是整数部分,y是小数部分)
//n^k=10^x * 10^y
//因为x是整数,所示10^x是1,10,100,1000…表示的是n^k有多少位,
//y是小数,10^y表示的是n^k的具体的数值。
//所以我们要求n^k的前a位,即求10^(a-1+y)
//(为什么是a-1? 答:指数函数10^x,当x>0时,10^x>1)
//https://blog.csdn.net/qq_43746332/article/details/96750087
求最大公约数函数
int gcd(int a,int b){
if(b == 0)
return a;
return gcd(b,a % b);
}