标签:acm模板
输入输出外挂
#include <cstdio>
#include <cstring>
int Scan() { //输入外挂
int res = 0, flag = 0;
char ch;
if((ch = getchar()) == ‘-‘) flag = 1;
else if(ch >= ‘0‘ && ch <= ‘9‘) res = ch - ‘0‘;
while((ch = getchar()) >= ‘0‘ && ch <= ‘9‘)
res = res * 10 + (ch - ‘0‘);
return flag ? -res : res;
}
void Out(int a) { //输出外挂
if(a < 0) { putchar(‘-‘); a = -a; }
if(a >= 10) Out(a / 10);
putchar(a % 10 + ‘0‘);
}
int main() {
int cnt[155];
int n, age;
while(~scanf("%d", &n)) {
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < n; i++) {
age = Scan();
cnt[age]++;
}
for(int i = 0; i <= 150; i++) {
if(cnt[i])
for(int j = 0; j < cnt[i]; j++)
Out(i), putchar(‘ ‘);
}
printf("\n");
}
return 0;
}
矩阵快速幂
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct Mat
{
int a[2][2];
};
Mat d;
int n=2,mod=10000;
Mat mul(Mat x,Mat y)
{
Mat t;
memset(t.a,0,sizeof(t.a));
/*矩阵乘法优化*/
for(int i=0;i<n;i++)
{
for(int k=0;k<n;k++)
{
if(x.a[i][k])//省去不必要的操作
{
for(int j=0;j<n;j++)
{
t.a[i][j]+=x.a[i][k]*y.a[k][j];
if(t.a[i][j]>=mod) t.a[i][j]%=mod;
}
}
}
}
return t;
}
Mat expo(Mat p,int k)//p^k
{
if(k==1)
return p;
Mat t;
memset(t.a,0,sizeof(t.a));
for(int i=0;i<n;i++)
t.a[i][i]=1;
if(k==0) return t;
while(k)
{
if(k&1) t=mul(p,t);
p=mul(p,p);
k>>=1;
}
return t;
}
int main()
{
d.a[1][1]=0;
d.a[1][0]=d.a[0][0]=d.a[0][1]=1;
int k;
while(~scanf("%d",&k))
{
if(k==-1)
break;
Mat ret=expo(d,k);
int ans=ret.a[0][1]%mod;
printf("%d\n",ans);
}
}
Spfa判环
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M = 100000 + 10;
struct Edge
{
int v, next;
};
int cnt;
Edge e[M<< 1];
int vis[M],head[M];
int f;//标记
void addEdge(int u, int v)
{
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt;
cnt++;
}
void topo(int s)
{
memset(vis,0, sizeof(vis));
vis[s]=1;
queue<int>tp;
tp.push(s);
while(!tp.empty())
{
int top=tp.front();
tp.pop();
for(int i=head[top];i!=-1;i=e[i].next)
{
int now=e[i].v;
vis[now]++;
if(vis[now]==1)
{
tp.push(now);
}
else
{
f=1;
return ;
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
int d=1;
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
int a,b;
scanf("%d%d",&a,&b);
int x,y;
cnt=0;
memset(head,-1,sizeof(head));
while(a--)
{
scanf("%d%d",&x,&y);
x++;
y++;
y+=n;
addEdge(x,y);
}
while(b--)
{
scanf("%d%d",&x,&y);
x++;
y++;
x+=n;
addEdge(x,y);
}
f=0;//标记
for(int i=1;i<=n;i++)
{
if(!f)
topo(i);
}
if(f) printf("Case %d: Possible\n",d++);
else printf("Case %d: Impossible\n",d++);
}
}
Spfa求最短路
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX_N = 100000 + 10;
const int INF = 0x3f3f3f3f;
struct Edge
{
int v, next;
};
int cnt, n, k, res, _count;
Edge e[MAX_N << 1];
int num[MAX_N], vis[MAX_N], head[MAX_N], d[MAX_N], has_army[MAX_N];
queue <int> Q;
void addEdge(int u, int v)
{
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt;
cnt++;
}
void SPFA(int src)//链式向前星
{
int u, v;
memset(vis, 0, sizeof(vis));
memset(d, INF, sizeof(d));
d[src] = 0;
queue<int> Q;
Q.push(src);
while(!Q.empty())
{
u = Q.front();
Q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = e[i].next)
{
v = e[i].v;
if(d[v] > d[u] + 1)
{
d[v] = d[u] + 1;
if(!vis[v])
{
Q.push(v);
vis[v] = true;
}
}
}
}
}
int main()
{
while(scanf("%d%d", &n, &k)!= EOF)
{
cnt = res = _count = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
if(num[i])
_count++;
}
memset(head, -1, sizeof(head));
for(int i = 0; i < k; i++)
scanf("%d", &has_army[i]);
int u, v;
for(int i = 0; i < n - 1; i++)
{
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
for(int i = 0; i < k; i++)
{
SPFA(has_army[i]);
for(int j = 1; j <= n; j++)
{
if(!num[j])
continue;
if(d[j] != INF)
{
res += num[j];
num[j] = 0;
_count--;
if(_count == 0)
break;
}
}
if(_count == 0)
break;
}
printf("%d\n", res);
}
return 0;
}
Sort 第k大
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
const int M=5e6+5;
int a[M];
int q_sort(int l,int r,int k)
{
if(l==r)
return a[l];
int s=l;
int e=r;
int f=a[l];
while(s<e)
{
while(s<e&&a[e]<=f) e--;
if(s<e)
a[s++]=a[e];
while(s<e&&a[s]>=f) s++;
if(s<e)
a[e--]=a[s];
}
a[s]=f;
if(s==k)
return a[s];
else if(s>k)
q_sort(l,s-1,k);
else
q_sort(s+1,r,k);
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
printf("%d\n",q_sort(1,n,k));}
Dijstra 优先队列优化
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int Ni = 10000;
const int INF = 1<<27;
struct node{
int x,d;
node(){}
node(int a,int b){x=a;d=b;}
bool operator < (const node & a) const
{
if(d==a.d) return x<a.x;
else return d > a.d;
}
};
vector<node> eg[Ni];
int dis[Ni],n;
void Dijkstra(int s)
{
int i;
for(i=0;i<=n;i++) dis[i]=INF;
dis[s]=0;
//用优先队列优化
priority_queue<node> q;
q.push(node(s,dis[s]));
while(!q.empty())
{
node x=q.top();q.pop();
for(i=0;i<eg[x.x].size();i++)
{
node y=eg[x.x][i];
if(dis[y.x]>x.d+y.d)
{
dis[y.x]=x.d+y.d;
q.push(node(y.x,dis[y.x]));
}
}
}
}
int main()
{
int a,b,d,m;
while(scanf("%d%d",&n,&m),n+m)
{
for(int i=0;i<=n;i++) eg[i].clear();
while(m--)
{
scanf("%d%d%d",&a,&b,&d);
eg[a].push_back(node(b,d));
eg[b].push_back(node(a,d));
}
Dijkstra(1);
printf("%d\n",dis[n]);
}
return 0;
}
/*
6 6
1 2 2
3 2 4
1 4 5
2 5 2
3 6 3
5 6 3
*/
Floyd多源最短路算法
#include<iostream>
#include<stdio.h>
using namespace std;
#define inf 9999999
int map[250][250];
int n,m;
int Floyd(int x,int y)
{
int t,i,j;
for(t=0; t<n; t++)
for(i=0; i<n; i++)
for(j=0; j<n; j++)
if(map[i][j]>map[i][t]+map[t][j])
{
map[i][j]=map[i][t]+map[t][j];
}
if(map[x][y]==inf) return -1;
else return map[x][y];
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int a,b,v,d,f,num;
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
map[i][j]=map[j][i]=inf;
for(int i=0; i<n; i++) //注意同一点的权值为0,刚开始wa在这儿
map[i][i]=0;
for(int i=0; i<m; i++)
{
cin>>a>>b>>v;
if(map[a][b]>v)
map[a][b]=map[b][a]=v;
}
cin>>d>>f;
num=Floyd(d,f);
cout<<num<<endl;
}
return 0;
}
----次小生成树
克里斯卡尔(筹建工程)
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int f[110];
struct load
{
int a,b,w;
}p[110];
int cmp(load s1,load s2)
{
return s1.w<s2.w;
}
int find(int x)
{
return f[x]==x?x:find(f[x]);
}
int kruskal(int n,int m)//n point m ·
{
int sum=0;
int i;
for(i=1;i<=n;i++)
{
f[i]=i;
}
sort(p,p+m,cmp);
for(i=0;i<m;i++)
{
int x=find(p[i].a);
int y=find(p[i].b);
if(x!=y) {sum+=p[i].w;f[x]=y;}
}
return sum;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>p[i].a>>p[i].b>>p[i].w;
}
if(n<m-1) {printf("No solution\n");continue;}
int ring=0;
for(int i=1;i<=m;i++) f[i]=i;
for(int i=0;i<n;i++)
{
int x=find(p[i].a);
int y=find(p[i].b);
if(x!=y)
{
f[x]=y;
}
}
for(int i=1;i<=m;i++)
{
if(f[i]==i)
ring++;
}
if(ring>1)
{
printf("No solution\n");
}
else
{
printf("%d\n",kruskal(m,n));
}
}
}
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
康拓展开
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
long long sum[15]={1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600}; //存的是0~12的阶乘..
int vis[15];
int main()
{
int t;
long long k,w,i,j;
scanf("%d",&t);
while(t--)
{
memset(vis,0,sizeof(vis));
long long n;
scanf("%lld",&n);
n=n-1;
for(i=12;i>0;i--)
{
w=n/sum[i-1];
n=n%sum[i-1];
k=0;
for(j=1;j<=12;j++)
{
if(vis[j]==0)
k++;
if(k==w+1)
break;
}
vis[j] = 1;
printf("%c",j+‘a‘-1);
}
printf("\n");
}
}
---------------------------------------------------
逆康拓展开
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int f(int n)
{
if(n==1||n==0)
return 1;
return n*f(n-1);
}
char str[15];
int main()
{
int t;
cin>>t;
while(t--)
{
for(int i=0;i<12;i++)
{
cin>>str[i];
str[i]-=96;
}
long long sum=1;
for(int i=0;i<12;i++)
{
int cnt=0;
for(int j=i;j<11;j++)
{
if(str[i]>str[j+1])
cnt++;
}
sum+=cnt*f(11-i);
}
cout<<sum<<endl;
}
}
多边形面积
#include<stdio.h>
#include<math.h>
struct ac
{
int x;
int y;
}a[105];
int main()
{
int n;
while(~scanf("%d",&n),n)
{
double sum=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
for(int i=1;i<n-1;i++)
{
sum+=(a[0].x*a[i+1].y+a[0].y*a[i].x+a[i+1].x*a[i].y-a[0].y*a[i+1].x-a[0].x*a[i].y-a[1+i].y*a[i].x)/2.0;
}
printf("%.1lf\n",-sum);
}
return 0;
}
n个点(顺序) 求n边形面积
#include<stdio.h>
#include<math.h>
int main()
{
int n;
int a[105],b[105],i;
while(~scanf("%d",&n))
{
double s=0;
for(i=0;i<n;i++)
scanf("%d%d",&a[i],&b[i]);
for(i=0;i<n-1;i++)
s+=(a[i]*b[i+1]*1.0-a[i+1]*b[i]*1.0);
s+=(a[n-1]*b[0]*1.0-a[0]*b[n-1]*1.0);
printf("%.2lf\n",fabs(s)/2.0);
}
return 0;
}
Kmp算法
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int M=1e6+5;
int next[M];
char s[M],t[M];
int cnt;
void getnext()
{
int i,j;
next[0]=-1;
for(i=1,j=-1;s[i];i++)
{
while(j!=-1&&s[i]!=s[j+1]) j=next[j];
if(s[i]==s[j+1]) j++;
next[i]=j;
}
}
void kmp()
{
int i,j;
cnt=0;
getnext();
for(i=0,j=-1; t[i]; i++)
{
while(j!=-1&&s[j+1]!=t[i]) j=next[j];
if(s[j+1]==t[i]) j++;
if(!s[j+1])
{
cnt++;
j=next[j];
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s%s",s,t);
kmp();
printf("%d\n",cnt);
}
return 0;
}
线性筛法求素数
#include<iostream>
using namespace std;
const int Max=2000000;
long long prime[Max] = {0};
int k=0;
int a[Max]={1,1};
void init()
{
for(long long i=2;i<Max;i++)
{
if(!a[i])//
prime[k++] = i;
for(long long j=0;j<k&&i*prime[j]<Max;j++)
{
a[i*prime[j]] = 1;
if(i%prime[j]==0)//
break;
}
}
}
int main()
{
int n;
init();
while(cin>>n)
{
for(int i=0;i<n;i++)
cout<<prime[i]<<" ";
cout<<endl;
}
}
大数卡特兰
#include<iostream>
using namespace std;
const int Max=2000000;
long long prime[Max] = {0};
int k=0;
int a[Max]={1,1};
void init()
{
for(long long i=2;i<Max;i++)
{
if(!a[i])//
prime[k++] = i;
for(long long j=0;j<k&&i*prime[j]<Max;j++)
{
a[i*prime[j]] = 1;
if(i%prime[j]==0)//
break;
}
}
}
int main()
{
int n;
init();
while(cin>>n)
{
for(int i=0;i<n;i++)
cout<<prime[i]<<" ";
cout<<endl;
}
}
坦克大战 优先队列优化
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int M=305;
char map[M][M];
bool vis[M][M];
int n,m;
int dir[4][2]= {1,0,-1,0,0,1,0,-1};
struct point
{
int x,y,t;
friend bool operator<(const point &a,const point &b)
{
return a.t>b.t;
}
};
point s,e;
int bfs()
{
priority_queue<point>tp;
s.t=0;
vis[s.x][s.y]=1;
tp.push(s);
point next;
while(!tp.empty())
{
s=tp.top();
tp.pop();
if(s.x==e.x&&s.y==e.y)
{
return s.t;
}
for(int i=0; i<4; ++i)
{
next.x=s.x+dir[i][0];
next.y=s.y+dir[i][1];
if(next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&vis[next.x][next.y]==0)
{
vis[next.x][next.y]=1;
if(map[next.x][next.y]==‘B‘)
{
next.t=s.t+2;
tp.push(next);
}
else if(map[next.x][next.y]==‘E‘||map[next.x][next.y]==‘T‘)
{
next.t=s.t+1;
tp.push(next);
}
}
}
}
return -1;
}
int main()
{
while(~scanf("%d%d",&n,&m),n||m)
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>map[i][j];
if(map[i][j]==‘Y‘)
{
s.x=i,s.y=j;
}
else if(map[i][j]==‘T‘)
{
e.x=i,e.y=j;
}
}
memset(vis,0,sizeof(vis));
int step=bfs();
printf("%d\n",step);
}
}
*****************************--------------**********************************
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<string>
using namespace std;
//#include<windows.h>
//#include<conio.h>
//freopen("1.txt","r",stdin);
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};//广搜优先队列
int n,m;//全局变量表示边界
bool guo[111][111];//标记此路已经走过
char map[111][111];//为地图
class sb
{
int x,y,bushu;//x,y表示坐标bushu表示当前的花费
public:
sb()
{}//构造函数
void chuzhi(int a,int b,int c)
{
x=a;
y=b;
bushu=c;
}//初值
friend bool operator< (sb n1, sb n2)
{
return n1.bushu > n2.bushu;
}//定义优先级
int x1()
{
return x;
}
int y1()
{
return y;
}
int jieguo()
{
return bushu;
}//这3个函数是得到当前私有变量的值
};
int bfs(sb a)//广搜
{
priority_queue <sb> jb;
jb.push(a);//定义优先队列把队顶元素初始化
mem(guo,0);//初始化
guo[a.x1()][a.y1()]=1;
while(!jb.empty())//为空就是无结果
{
a=jb.top();
jb.pop();//取队顶元素,此元素为当前队列里面花费最少的元素,也是目前的最短路
for(int i=0; i<4; i++)//表示4个方向
{
int p=a.x1()+dir[i][0];
int q=a.y1()+dir[i][1];
if(p<0||p>=n||q<0||q>=m)
continue;//越界
if(map[p][q]==‘l‘)
return a.jieguo();//得到结果
if(map[p][q]!=‘#‘&&guo[p][q]!=1)//如果此路可行就把结果放入队列中
{
guo[p][q]=1;//标记此路已经走过,而且此点一定是当前到达此点的最小值
sb b;
b.chuzhi(p,q,a.jieguo()+map[p][q]-‘A‘+1);
jb.push(b);
}
}
}
return -1;//无路可走
}
int main()
{
int T,i,j;
cin>>T;
while(T--)
{
cin>>n>>m;
sb a;
for(i=0; i<n; i++)
{
getchar();
for(j=0; j<m; j++)
{
map[i][j]=getchar();
if(map[i][j]==‘s‘)
a.chuzhi(i,j,0);
}//输入
}
cout<<bfs(a)<<endl;//结果
}
}
---j-----------------j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j-j------------
#include<stdio.h>
#include<string.h>
#include<stack> /*定义栈*/
using namespace std; /*千万不要忘记*/
int main()
{
int n,i,j,k,flag[20];
char s1[10],s2[10];
stack<char> s;
while(~scanf("%d%s %s",&n,s1,s2))
{
memset(flag,-1,sizeof(flag));
j=k=0;
for(i=0;i<n;i++)
{
s.push(s1[i]);
flag[k++]=1; /*1为进栈,in*/
while(!s.empty()&&s.top()==s2[j]) /*栈非空且栈顶元素与s2中的元素相等*/
{
flag[k++]=0; /*0为出栈,out*/
s.pop(); /*清除栈顶元素*/
j++; /*与s2中的下一个元素比较*/
}
}
if(j==n) /*可以转换*/
{
printf("Yes.\n");
for(i=0;i<k;i++)
{
if(flag[i]) /*flag[i]==1*/
printf("in\n");
else
printf("out\n");
}
printf("FINISH\n");
}
else /*不能转换*/
printf("No.\nFINISH\n");
}
return 0;
}
优先队列:顾名思义,首先它是一个队列,但是它强调了“优先”二字,所以,已经不能算是一般意义上的队列了,它的“优先”意指取队首元素时,有一定的选择性,即根据元素的属性选择某一项值最优的出队~
百度百科上这样描述的:
优先级队列 是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素
优先队列的类定义
优先队列是0个或多个元素的集合,每个元素都有一个优先权或值,对优先队列执行的操作有1) 查找;2) 插入一个新元素;3) 删除.在最小优先队列(min priorityq u e u e)中,查找操作用来搜索优先权最小的元素,删除操作用来删除该元素;对于最大优先队列(max priority queue),查找操作用来搜索优先权最大的元素,删除操作用来删除该元素.优先权队列中的元素可以有相同的优先权,查找与删除操作可根据任意优先权进行.
优先队列,其构造及具体实现我们可以先不用深究,我们现在只需要了解其特性,及在做题中的用法,相信,看过之后你会收获不少。
使用优先队列,首先要包函STL头文件"queue",
以一个例子来解释吧(呃,写完才发现,这个代码包函了几乎所有我们要用到的用法,仔细看看吧):
view plaincopy to clipboardprint?
/*优先队列的基本使用 2010/7/24 dooder*/
#include<stdio.h>
#include<functional>
#include<queue>
#include<vector>
using namespace std;
//定义结构,使用运算符重载,自定义优先级1
struct cmp1{
bool operator ()(int &a,int &b){
return a>b;//最小值优先
}
};
struct cmp2{
bool operator ()(int &a,int &b){
return a<b;//最大值优先
}
};
//定义结构,使用运算符重载,自定义优先级2
struct number1{
int x;
bool operator < (const number1 &a) const {
return x>a.x;//最小值优先
}
};
struct number2{
int x;
bool operator < (const number2 &a) const {
return x<a.x;//最大值优先
}
};
int a[]={14,10,56,7,83,22,36,91,3,47,72,0};
number1 num1[]={14,10,56,7,83,22,36,91,3,47,72,0};
number2 num2[]={14,10,56,7,83,22,36,91,3,47,72,0};
int main()
{ priority_queue<int>que;//采用默认优先级构造队列
priority_queue<int,vector<int>,cmp1>que1;//最小值优先
priority_queue<int,vector<int>,cmp2>que2;//最大值优先
priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,
//这是右移运算符,所以这里用空格号隔开
priority_queue<int,vector<int>,less<int> >que4;////最大值优先
priority_queue<number1>que5;
priority_queue<number2>que6;
int i;
for(i=0;a[i];i++){
que.push(a[i]);
que1.push(a[i]);
que2.push(a[i]);
que3.push(a[i]);
que4.push(a[i]);
}
for(i=0;num1[i].x;i++)
que5.push(num1[i]);
for(i=0;num2[i].x;i++)
que6.push(num2[i]);
printf("采用默认优先关系:\n(priority_queue<int>que;)\n");
printf("Queue 0:\n");
while(!que.empty()){
printf("%3d",que.top());
que.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式一:\n(priority_queue<int,vector<int>,cmp>que;)\n");
printf("Queue 1:\n");
while(!que1.empty()){
printf("%3d",que1.top());
que1.pop();
}
puts("");
printf("Queue 2:\n");
while(!que2.empty()){
printf("%3d",que2.top());
que2.pop();
}
puts("");
puts("");
printf("采用头文件\"functional\"内定义优先级:\n(priority_queue<int,vector<int>,greater<int>/less<int> >que;)\n");
printf("Queue 3:\n");
while(!que3.empty()){
printf("%3d",que3.top());
que3.pop();
}
puts("");
printf("Queue 4:\n");
while(!que4.empty()){
printf("%3d",que4.top());
que4.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式二:\n(priority_queue<number>que)\n");
printf("Queue 5:\n");
while(!que5.empty()){
printf("%3d",que5.top());
que5.pop();
}
puts("");
printf("Queue 6:\n");
while(!que6.empty()){
printf("%3d",que6.top());
que6.pop();
}
puts("");
return 0;
}
/*
运行结果 :
采用默认优先关系:
(priority_queue<int>que;)
Queue 0:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式一:
(priority_queue<int,vector<int>,cmp>que;)
Queue 1:
3 7 10 14 22 36 47 56 72 83 91
Queue 2:
91 83 72 56 47 36 22 14 10 7 3
采用头文件"functional"内定义优先级:
(priority_queue<int,vector<int>,greater<int>/less<int> >que;)
Queue 3:
3 7 10 14 22 36 47 56 72 83 91
Queue 4:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式二:
(priority_queue<number>que)
Queue 5:
3 7 10 14 22 36 47 56 72 83 91
Queue 6:
91 83 72 56 47 36 22 14 10 7 3
*/
运行结果:
采用默认优先关系:
(priority_queue<int>que;)
Queue 0:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式一:
(priority_queue<int,vector<int>,cmp>que;)
Queue 1:
3 7 10 14 22 36 47 56 72 83 91
Queue 2:
91 83 72 56 47 36 22 14 10 7 3
采用头文件"functional"内定义优先级:
(priority_queue<int,vector<int>,greater<int>/less<int> >que;)
Queue 3:
3 7 10 14 22 36 47 56 72 83 91
Queue 4:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式二:
(priority_queue<number>que)
Queue 5:
3 7 10 14 22 36 47 56 72 83 91
Queue 6:
91 83 72 56 47 36 22 14 10 7 3
好了,如果你仔细看完了上面的代码,那么你就可以基本使用优先队列了,下面给出一些我做题中有过的一些应用,希望能给大家带来一些启
示~
1、先来一个我们最近做的题吧,http://acm.hdu.edu.cn/showproblem.php?pid=1242
题意:某人被关在囚笼里等待朋友解救,问能否解救成功,最少需要多少时间~
具体:可同时有几个朋友,每走一格消耗一分钟的时间 ,地图上还存在着卫兵,卫兵可以解决掉,但是要另外花费一分钟~
分析:从“a”出发,此题可以用回溯法进行深搜,但那样做的话,效率还是不能让人满意,但是广搜的话,由于入队后每次出队时,根据地
图情况的不同,出队元素所记忆的时间并不是层次递增的,因此使用简单广搜的话,同样需要全部搜索才能找到正确答案。有没有一种方法能
让某一步因为遇到士兵而多花时间的结点在队列中向后推迟一层出队呢?答案是肯定的,在这里我们可以用优先队列来实现,总体思想上是,
根据时间进行优先性选择,每次都要出队当前队列元素中记录时间最少的出队,而入队处理时,我们可以按顺序对四个方向上的各种情况按正
常处理入队就行了,出队顺序由优先队列根据预设优先性自动控制。这样,我们就可以从“a”进行基于优先队列的范围搜索了,并且在第一
次抵达有朋友的位置时得到正确结果~具体实现代码:
view plaincopy to clipboardprint?
/*HDU 1242 基于优先队列的范围搜索,16ms dooder*/
#include<stdio.h>
#include<queue>
using namespace std;
#define M 201
typedef struct p{
int x,y,t;
bool operator < (const p &a)const
{
return t>a.t;//取时间最少优先
}
}Point;
char map[M][M];
Point start;
int n,m;
int dir[][2]={{1,0},{-1,0},{0,1},{0,-1}};
int bfs()
{
priority_queue<Point>que;
Point cur,next;
int i;
map[start.x][start.y]=‘#‘;
que.push(start);
while(!que.empty()){
cur=que.top();//由优先队列自动完成出队时间最少的元素
que.pop();
for(i=0;i<4;i++){
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
next.t=cur.t+1;
if(next.x<0||next.x>=n||next.y<0||next.y>=m)
continue;
if(map[next.x][next.y]==‘#‘)
continue;
if(map[next.x][next.y]==‘r‘)
return next.t;
if(map[next.x][next.y]==‘.‘){
map[next.x][next.y]=‘#‘;
que.push(next);
}
else if(map[next.x][next.y]==‘x‘){
map[next.x][next.y]=‘#‘;
next.t++;
que.push(next);
}
}
}
return -1;
}
int main()
{
int i,ans;
char *p;
while(scanf("%d%d",&n,&m)!=-1){
for(i=0;i<n;i++){
scanf("%s",map[i]);
if(p=strchr(map[i],‘a‘)){
start.x=i;
start.y=p-map[i];
start.t=0;
}
}
ans=bfs();
printf(ans+1?"%d\n":"Poor ANGEL has to stay in the prison all his life.\n",ans);
}
return 0;
}
2、http://acm.hdu.edu.cn/showproblem.php?pid=1053
题意:给出一行字符串,求出其原编码需要的编码长度和哈夫曼编码所需的长度,并求其比值
分析:根据哈夫曼生成树的生成过程可知,其生成树的权值是固定的而且这个值是最小的,而且其值根据生成树的顺序,我们可以找出规律而
不需要真的去生成一棵树然后再求出权值,其模拟过程为取出队列中权值最小的两个元素,将其值加入结果中,然后将这两个元素的权值求和
即得出其父节点的权值,将生成元素作为结点入队~~如此循环,直至取出队列中最后两个元素加入结果,实现代码如下:
view plaincopy to clipboardprint?
/*HDU 1053 采用广搜求哈夫曼生成树的权值 0ms dooder*/
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<functional>
#include<queue>
using namespace std;
#define M 1000050
char str[M];
int list[27];
priority_queue< int,vector<int>,greater<int> >que;
int main()
{
int ans,sum;
int i,a,b,c;
while(scanf("%s",str),strcmp(str,"END")){
memset(list,0,sizeof(list));
for(i=0;str[i];i++){
if(isalpha(str[i]))
list[str[i]-‘A‘]++;
else
list[26]++;
}
sum=i*8;ans=i;c=0;
for(i=0;i<27;i++){
if(list[i]){
que.push(list[i]);
c++;
}
}
if(c>1){ans=0;//注意只有一种字符的情况
while(que.size()!=1){
a=que.top();
que.pop();
b=que.top();
que.pop();
ans+=a+b;
que.push(a+b);
}
while(!que.empty())//使用后清空队列
que.pop();
}
printf("%d %d %.1f\n",sum,ans,1.0*sum/ans);
}
return 0;
}
3、http://acm.pku.edu.cn/JudgeOnline/problem?id=2263
这是第二次练习赛时,我们做过的最后一题,这里采用优先队列进行实现,在《谁说不能这样做题》中已提到这种方法,在这里再次放出代
码,~
题意:给出各城市间道路的限制载重量,求出从一个城市到另外一个城市的贷车能够运载的最大货物重量。
分析:采用优先队列,每次取出当前队列中结点的minheavy最大值出队,对它的连接结点搜索入队,这样,从出发点开始就可以
在到达终点时求出结果,即最大载货物重,实现代码如下:
view plaincopy to clipboardprint?
/*POJ 2263 16ms dooder*/
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define M 201
typedef struct w{
int city;
int mintons;
bool operator < (const w &a)const {
return mintons < a.mintons;
}//优先性定义
}Way;
char citys[M][31];
int map[M][M];
bool mark[M][M];
int n,m,from,to,ans,k;
priority_queue <Way> que;
int min(int a,int b)
{
return a>b?b:a;
}
void bfs()
{
Way cur,next;
int i;
while(!que.empty()){
cur=que.top();
que.pop();
if(cur.city==to){
if(cur.mintons>ans)
ans=cur.mintons;
while(!que.empty())
que.pop();
return ;
}
for(i=0;i<n;i++){
if(map[cur.city][i]&&!mark[cur.city][i]){
next.city=i;
next.mintons=min(cur.mintons,map[cur.city][i]);
mark[cur.city][i]=mark[i][cur.city]=1;
que.push(next);
}
}
}
}
void run()
{
int i,temp,index;
Way cur;
ans=0;
memset(mark,0,sizeof(mark));
temp=0;
for(i=0;i<n;i++){
if(map[from][i]>temp){
temp=map[from][i];
index=i;
}
}
cur.city=index;
cur.mintons=temp;
que.push(cur);
bfs();
}
int main()
{
int k1,k2,tons,t=1;
char s1[31],s2[31];
while(scanf("%d%d",&n,&m),n||m){
k=0;
while(m--){
scanf("%s%s%d",s1,s2,&tons);
for(k1=0;strcmp(s1,citys[k1])&&k1<k;k1++);
if(k1==k)
strcpy(citys[k++],s1);
for(k2=0;strcmp(s2,citys[k2])&&k2<k;k2++);
if(k2==k)
strcpy(citys[k++],s2);
map[k1][k2]=map[k2][k1]=tons;
}
scanf("%s%s",s1,s2);
for(from=0;strcmp(citys[from],s1);from++);
for(to=0;strcmp(citys[to],s2);to++);
run();
printf("Scenario #%d\n",t++);
printf("%d tons\n\n",ans);
}
return 0;
}
当然了,优先队列的用法决不是仅仅提到的这些,各种应用还需要大家去发现,给道题大家可以练习一下hdu 2066\
相信大家已经学到不少了,还有一点可以告诉大家,优先队列是启发式搜索的数据结构基础,希望好好理解,并逐步掌握其用法~
加:失策啊,竟然忘了说优先队列的效率了,其时间复杂度为O(logn).n为队列中元素的个数,存取都需要消耗时间~优先队列:顾名思义,首先它是一个队列,但是它强调了“优先”二字,所以,已经不能算是一般意义上的队列了,它的“优先”意指取队首元素时,有一定的选择性,即根据元素的属性选择某一项值最优的出队~
百度百科上这样描述的:
优先级队列 是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素
优先队列的类定义
优先队列是0个或多个元素的集合,每个元素都有一个优先权或值,对优先队列执行的操作有1) 查找;2) 插入一个新元素;3) 删除.在最小优先队列(min priorityq u e u e)中,查找操作用来搜索优先权最小的元素,删除操作用来删除该元素;对于最大优先队列(max priority queue),查找操作用来搜索优先权最大的元素,删除操作用来删除该元素.优先权队列中的元素可以有相同的优先权,查找与删除操作可根据任意优先权进行.
优先队列,其构造及具体实现我们可以先不用深究,我们现在只需要了解其特性,及在做题中的用法,相信,看过之后你会收获不少。
使用优先队列,首先要包函STL头文件"queue",
以一个例子来解释吧(呃,写完才发现,这个代码包函了几乎所有我们要用到的用法,仔细看看吧):
view plaincopy to clipboardprint?
/*优先队列的基本使用 2010/7/24 dooder*/
#include<stdio.h>
#include<functional>
#include<queue>
#include<vector>
using namespace std;
//定义结构,使用运算符重载,自定义优先级1
struct cmp1{
bool operator ()(int &a,int &b){
return a>b;//最小值优先
}
};
struct cmp2{
bool operator ()(int &a,int &b){
return a<b;//最大值优先
}
};
//定义结构,使用运算符重载,自定义优先级2
struct number1{
int x;
bool operator < (const number1 &a) const {
return x>a.x;//最小值优先
}
};
struct number2{
int x;
bool operator < (const number2 &a) const {
return x<a.x;//最大值优先
}
};
int a[]={14,10,56,7,83,22,36,91,3,47,72,0};
number1 num1[]={14,10,56,7,83,22,36,91,3,47,72,0};
number2 num2[]={14,10,56,7,83,22,36,91,3,47,72,0};
int main()
{ priority_queue<int>que;//采用默认优先级构造队列
priority_queue<int,vector<int>,cmp1>que1;//最小值优先
priority_queue<int,vector<int>,cmp2>que2;//最大值优先
priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,
//这是右移运算符,所以这里用空格号隔开
priority_queue<int,vector<int>,less<int> >que4;////最大值优先
priority_queue<number1>que5;
priority_queue<number2>que6;
int i;
for(i=0;a[i];i++){
que.push(a[i]);
que1.push(a[i]);
que2.push(a[i]);
que3.push(a[i]);
que4.push(a[i]);
}
for(i=0;num1[i].x;i++)
que5.push(num1[i]);
for(i=0;num2[i].x;i++)
que6.push(num2[i]);
printf("采用默认优先关系:\n(priority_queue<int>que;)\n");
printf("Queue 0:\n");
while(!que.empty()){
printf("%3d",que.top());
que.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式一:\n(priority_queue<int,vector<int>,cmp>que;)\n");
printf("Queue 1:\n");
while(!que1.empty()){
printf("%3d",que1.top());
que1.pop();
}
puts("");
printf("Queue 2:\n");
while(!que2.empty()){
printf("%3d",que2.top());
que2.pop();
}
puts("");
puts("");
printf("采用头文件\"functional\"内定义优先级:\n(priority_queue<int,vector<int>,greater<int>/less<int> >que;)\n");
printf("Queue 3:\n");
while(!que3.empty()){
printf("%3d",que3.top());
que3.pop();
}
puts("");
printf("Queue 4:\n");
while(!que4.empty()){
printf("%3d",que4.top());
que4.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式二:\n(priority_queue<number>que)\n");
printf("Queue 5:\n");
while(!que5.empty()){
printf("%3d",que5.top());
que5.pop();
}
puts("");
printf("Queue 6:\n");
while(!que6.empty()){
printf("%3d",que6.top());
que6.pop();
}
puts("");
return 0;
}
/*
运行结果 :
采用默认优先关系:
(priority_queue<int>que;)
Queue 0:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式一:
(priority_queue<int,vector<int>,cmp>que;)
Queue 1:
3 7 10 14 22 36 47 56 72 83 91
Queue 2:
91 83 72 56 47 36 22 14 10 7 3
采用头文件"functional"内定义优先级:
(priority_queue<int,vector<int>,greater<int>/less<int> >que;)
Queue 3:
3 7 10 14 22 36 47 56 72 83 91
Queue 4:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式二:
(priority_queue<number>que)
Queue 5:
3 7 10 14 22 36 47 56 72 83 91
Queue 6:
91 83 72 56 47 36 22 14 10 7 3
*/
运行结果:
采用默认优先关系:
(priority_queue<int>que;)
Queue 0:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式一:
(priority_queue<int,vector<int>,cmp>que;)
Queue 1:
3 7 10 14 22 36 47 56 72 83 91
Queue 2:
91 83 72 56 47 36 22 14 10 7 3
采用头文件"functional"内定义优先级:
(priority_queue<int,vector<int>,greater<int>/less<int> >que;)
Queue 3:
3 7 10 14 22 36 47 56 72 83 91
Queue 4:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式二:
(priority_queue<number>que)
Queue 5:
3 7 10 14 22 36 47 56 72 83 91
Queue 6:
91 83 72 56 47 36 22 14 10 7 3
好了,如果你仔细看完了上面的代码,那么你就可以基本使用优先队列了,下面给出一些我做题中有过的一些应用,希望能给大家带来一些启
示~
1、先来一个我们最近做的题吧,http://acm.hdu.edu.cn/showproblem.php?pid=1242
题意:某人被关在囚笼里等待朋友解救,问能否解救成功,最少需要多少时间~
具体:可同时有几个朋友,每走一格消耗一分钟的时间 ,地图上还存在着卫兵,卫兵可以解决掉,但是要另外花费一分钟~
分析:从“a”出发,此题可以用回溯法进行深搜,但那样做的话,效率还是不能让人满意,但是广搜的话,由于入队后每次出队时,根据地
图情况的不同,出队元素所记忆的时间并不是层次递增的,因此使用简单广搜的话,同样需要全部搜索才能找到正确答案。有没有一种方法能
让某一步因为遇到士兵而多花时间的结点在队列中向后推迟一层出队呢?答案是肯定的,在这里我们可以用优先队列来实现,总体思想上是,
根据时间进行优先性选择,每次都要出队当前队列元素中记录时间最少的出队,而入队处理时,我们可以按顺序对四个方向上的各种情况按正
常处理入队就行了,出队顺序由优先队列根据预设优先性自动控制。这样,我们就可以从“a”进行基于优先队列的范围搜索了,并且在第一
次抵达有朋友的位置时得到正确结果~具体实现代码:
view plaincopy to clipboardprint?
/*HDU 1242 基于优先队列的范围搜索,16ms dooder*/
#include<stdio.h>
#include<queue>
using namespace std;
#define M 201
typedef struct p{
int x,y,t;
bool operator < (const p &a)const
{
return t>a.t;//取时间最少优先
}
}Point;
char map[M][M];
Point start;
int n,m;
int dir[][2]={{1,0},{-1,0},{0,1},{0,-1}};
int bfs()
{
priority_queue<Point>que;
Point cur,next;
int i;
map[start.x][start.y]=‘#‘;
que.push(start);
while(!que.empty()){
cur=que.top();//由优先队列自动完成出队时间最少的元素
que.pop();
for(i=0;i<4;i++){
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
next.t=cur.t+1;
if(next.x<0||next.x>=n||next.y<0||next.y>=m)
continue;
if(map[next.x][next.y]==‘#‘)
continue;
if(map[next.x][next.y]==‘r‘)
return next.t;
if(map[next.x][next.y]==‘.‘){
map[next.x][next.y]=‘#‘;
que.push(next);
}
else if(map[next.x][next.y]==‘x‘){
map[next.x][next.y]=‘#‘;
next.t++;
que.push(next);
}
}
}
return -1;
}
int main()
{
int i,ans;
char *p;
while(scanf("%d%d",&n,&m)!=-1){
for(i=0;i<n;i++){
scanf("%s",map[i]);
if(p=strchr(map[i],‘a‘)){
start.x=i;
start.y=p-map[i];
start.t=0;
}
}
ans=bfs();
printf(ans+1?"%d\n":"Poor ANGEL has to stay in the prison all his life.\n",ans);
}
return 0;
}
2、http://acm.hdu.edu.cn/showproblem.php?pid=1053
题意:给出一行字符串,求出其原编码需要的编码长度和哈夫曼编码所需的长度,并求其比值
分析:根据哈夫曼生成树的生成过程可知,其生成树的权值是固定的而且这个值是最小的,而且其值根据生成树的顺序,我们可以找出规律而
不需要真的去生成一棵树然后再求出权值,其模拟过程为取出队列中权值最小的两个元素,将其值加入结果中,然后将这两个元素的权值求和
即得出其父节点的权值,将生成元素作为结点入队~~如此循环,直至取出队列中最后两个元素加入结果,实现代码如下:
view plaincopy to clipboardprint?
/*HDU 1053 采用广搜求哈夫曼生成树的权值 0ms dooder*/
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<functional>
#include<queue>
using namespace std;
#define M 1000050
char str[M];
int list[27];
priority_queue< int,vector<int>,greater<int> >que;
int main()
{
int ans,sum;
int i,a,b,c;
while(scanf("%s",str),strcmp(str,"END")){
memset(list,0,sizeof(list));
for(i=0;str[i];i++){
if(isalpha(str[i]))
list[str[i]-‘A‘]++;
else
list[26]++;
}
sum=i*8;ans=i;c=0;
for(i=0;i<27;i++){
if(list[i]){
que.push(list[i]);
c++;
}
}
if(c>1){ans=0;//注意只有一种字符的情况
while(que.size()!=1){
a=que.top();
que.pop();
b=que.top();
que.pop();
ans+=a+b;
que.push(a+b);
}
while(!que.empty())//使用后清空队列
que.pop();
}
printf("%d %d %.1f\n",sum,ans,1.0*sum/ans);
}
return 0;
}
3、http://acm.pku.edu.cn/JudgeOnline/problem?id=2263
这是第二次练习赛时,我们做过的最后一题,这里采用优先队列进行实现,在《谁说不能这样做题》中已提到这种方法,在这里再次放出代
码,~
题意:给出各城市间道路的限制载重量,求出从一个城市到另外一个城市的贷车能够运载的最大货物重量。
分析:采用优先队列,每次取出当前队列中结点的minheavy最大值出队,对它的连接结点搜索入队,这样,从出发点开始就可以
在到达终点时求出结果,即最大载货物重,实现代码如下:
view plaincopy to clipboardprint?
/*POJ 2263 16ms dooder*/
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define M 201
typedef struct w{
int city;
int mintons;
bool operator < (const w &a)const {
return mintons < a.mintons;
}//优先性定义
}Way;
char citys[M][31];
int map[M][M];
bool mark[M][M];
int n,m,from,to,ans,k;
priority_queue <Way> que;
int min(int a,int b)
{
return a>b?b:a;
}
void bfs()
{
Way cur,next;
int i;
while(!que.empty()){
cur=que.top();
que.pop();
if(cur.city==to){
if(cur.mintons>ans)
ans=cur.mintons;
while(!que.empty())
que.pop();
return ;
}
for(i=0;i<n;i++){
if(map[cur.city][i]&&!mark[cur.city][i]){
next.city=i;
next.mintons=min(cur.mintons,map[cur.city][i]);
mark[cur.city][i]=mark[i][cur.city]=1;
que.push(next);
}
}
}
}
void run()
{
int i,temp,index;
Way cur;
ans=0;
memset(mark,0,sizeof(mark));
temp=0;
for(i=0;i<n;i++){
if(map[from][i]>temp){
temp=map[from][i];
index=i;
}
}
cur.city=index;
cur.mintons=temp;
que.push(cur);
bfs();
}
int main()
{
int k1,k2,tons,t=1;
char s1[31],s2[31];
while(scanf("%d%d",&n,&m),n||m){
k=0;
while(m--){
scanf("%s%s%d",s1,s2,&tons);
for(k1=0;strcmp(s1,citys[k1])&&k1<k;k1++);
if(k1==k)
strcpy(citys[k++],s1);
for(k2=0;strcmp(s2,citys[k2])&&k2<k;k2++);
if(k2==k)
strcpy(citys[k++],s2);
map[k1][k2]=map[k2][k1]=tons;
}
scanf("%s%s",s1,s2);
for(from=0;strcmp(citys[from],s1);from++);
for(to=0;strcmp(citys[to],s2);to++);
run();
printf("Scenario #%d\n",t++);
printf("%d tons\n\n",ans);
}
return 0;
}
当然了,优先队列的用法决不是仅仅提到的这些,各种应用还需要大家去发现,给道题大家可以练习一下hdu 2066\
相信大家已经学到不少了,还有一点可以告诉大家,优先队列是启发式搜索的数据结构基础,希望好好理解,并逐步掌握其用法~
加:失策啊,竟然忘了说优先队列的效率了,其时间复杂度为O(logn).n为队列中元素的个数,存取都需要消耗时间~优先队列:顾名思义,首先它是一个队列,但是它强调了“优先”二字,所以,已经不能算是一般意义上的队列了,它的“优先”意指取队首元素时,有一定的选择性,即根据元素的属性选择某一项值最优的出队~
百度百科上这样描述的:
优先级队列 是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素
优先队列的类定义
优先队列是0个或多个元素的集合,每个元素都有一个优先权或值,对优先队列执行的操作有1) 查找;2) 插入一个新元素;3) 删除.在最小优先队列(min priorityq u e u e)中,查找操作用来搜索优先权最小的元素,删除操作用来删除该元素;对于最大优先队列(max priority queue),查找操作用来搜索优先权最大的元素,删除操作用来删除该元素.优先权队列中的元素可以有相同的优先权,查找与删除操作可根据任意优先权进行.
优先队列,其构造及具体实现我们可以先不用深究,我们现在只需要了解其特性,及在做题中的用法,相信,看过之后你会收获不少。
使用优先队列,首先要包函STL头文件"queue",
以一个例子来解释吧(呃,写完才发现,这个代码包函了几乎所有我们要用到的用法,仔细看看吧):
view plaincopy to clipboardprint?
/*优先队列的基本使用 2010/7/24 dooder*/
#include<stdio.h>
#include<functional>
#include<queue>
#include<vector>
using namespace std;
//定义结构,使用运算符重载,自定义优先级1
struct cmp1{
bool operator ()(int &a,int &b){
return a>b;//最小值优先
}
};
struct cmp2{
bool operator ()(int &a,int &b){
return a<b;//最大值优先
}
};
//定义结构,使用运算符重载,自定义优先级2
struct number1{
int x;
bool operator < (const number1 &a) const {
return x>a.x;//最小值优先
}
};
struct number2{
int x;
bool operator < (const number2 &a) const {
return x<a.x;//最大值优先
}
};
int a[]={14,10,56,7,83,22,36,91,3,47,72,0};
number1 num1[]={14,10,56,7,83,22,36,91,3,47,72,0};
number2 num2[]={14,10,56,7,83,22,36,91,3,47,72,0};
int main()
{ priority_queue<int>que;//采用默认优先级构造队列
priority_queue<int,vector<int>,cmp1>que1;//最小值优先
priority_queue<int,vector<int>,cmp2>que2;//最大值优先
priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,
//这是右移运算符,所以这里用空格号隔开
priority_queue<int,vector<int>,less<int> >que4;////最大值优先
priority_queue<number1>que5;
priority_queue<number2>que6;
int i;
for(i=0;a[i];i++){
que.push(a[i]);
que1.push(a[i]);
que2.push(a[i]);
que3.push(a[i]);
que4.push(a[i]);
}
for(i=0;num1[i].x;i++)
que5.push(num1[i]);
for(i=0;num2[i].x;i++)
que6.push(num2[i]);
printf("采用默认优先关系:\n(priority_queue<int>que;)\n");
printf("Queue 0:\n");
while(!que.empty()){
printf("%3d",que.top());
que.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式一:\n(priority_queue<int,vector<int>,cmp>que;)\n");
printf("Queue 1:\n");
while(!que1.empty()){
printf("%3d",que1.top());
que1.pop();
}
puts("");
printf("Queue 2:\n");
while(!que2.empty()){
printf("%3d",que2.top());
que2.pop();
}
puts("");
puts("");
printf("采用头文件\"functional\"内定义优先级:\n(priority_queue<int,vector<int>,greater<int>/less<int> >que;)\n");
printf("Queue 3:\n");
while(!que3.empty()){
printf("%3d",que3.top());
que3.pop();
}
puts("");
printf("Queue 4:\n");
while(!que4.empty()){
printf("%3d",que4.top());
que4.pop();
}
puts("");
puts("");
printf("采用结构体自定义优先级方式二:\n(priority_queue<number>que)\n");
printf("Queue 5:\n");
while(!que5.empty()){
printf("%3d",que5.top());
que5.pop();
}
puts("");
printf("Queue 6:\n");
while(!que6.empty()){
printf("%3d",que6.top());
que6.pop();
}
puts("");
return 0;
}
/*
运行结果 :
采用默认优先关系:
(priority_queue<int>que;)
Queue 0:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式一:
(priority_queue<int,vector<int>,cmp>que;)
Queue 1:
3 7 10 14 22 36 47 56 72 83 91
Queue 2:
91 83 72 56 47 36 22 14 10 7 3
采用头文件"functional"内定义优先级:
(priority_queue<int,vector<int>,greater<int>/less<int> >que;)
Queue 3:
3 7 10 14 22 36 47 56 72 83 91
Queue 4:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式二:
(priority_queue<number>que)
Queue 5:
3 7 10 14 22 36 47 56 72 83 91
Queue 6:
91 83 72 56 47 36 22 14 10 7 3
*/
运行结果:
采用默认优先关系:
(priority_queue<int>que;)
Queue 0:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式一:
(priority_queue<int,vector<int>,cmp>que;)
Queue 1:
3 7 10 14 22 36 47 56 72 83 91
Queue 2:
91 83 72 56 47 36 22 14 10 7 3
采用头文件"functional"内定义优先级:
(priority_queue<int,vector<int>,greater<int>/less<int> >que;)
Queue 3:
3 7 10 14 22 36 47 56 72 83 91
Queue 4:
91 83 72 56 47 36 22 14 10 7 3
采用结构体自定义优先级方式二:
(priority_queue<number>que)
Queue 5:
3 7 10 14 22 36 47 56 72 83 91
Queue 6:
91 83 72 56 47 36 22 14 10 7 3
好了,如果你仔细看完了上面的代码,那么你就可以基本使用优先队列了,下面给出一些我做题中有过的一些应用,希望能给大家带来一些启
示~
1、先来一个我们最近做的题吧,http://acm.hdu.edu.cn/showproblem.php?pid=1242
题意:某人被关在囚笼里等待朋友解救,问能否解救成功,最少需要多少时间~
具体:可同时有几个朋友,每走一格消耗一分钟的时间 ,地图上还存在着卫兵,卫兵可以解决掉,但是要另外花费一分钟~
分析:从“a”出发,此题可以用回溯法进行深搜,但那样做的话,效率还是不能让人满意,但是广搜的话,由于入队后每次出队时,根据地
图情况的不同,出队元素所记忆的时间并不是层次递增的,因此使用简单广搜的话,同样需要全部搜索才能找到正确答案。有没有一种方法能
让某一步因为遇到士兵而多花时间的结点在队列中向后推迟一层出队呢?答案是肯定的,在这里我们可以用优先队列来实现,总体思想上是,
根据时间进行优先性选择,每次都要出队当前队列元素中记录时间最少的出队,而入队处理时,我们可以按顺序对四个方向上的各种情况按正
常处理入队就行了,出队顺序由优先队列根据预设优先性自动控制。这样,我们就可以从“a”进行基于优先队列的范围搜索了,并且在第一
次抵达有朋友的位置时得到正确结果~具体实现代码:
view plaincopy to clipboardprint?
/*HDU 1242 基于优先队列的范围搜索,16ms dooder*/
#include<stdio.h>
#include<queue>
using namespace std;
#define M 201
typedef struct p{
int x,y,t;
bool operator < (const p &a)const
{
return t>a.t;//取时间最少优先
}
}Point;
char map[M][M];
Point start;
int n,m;
int dir[][2]={{1,0},{-1,0},{0,1},{0,-1}};
int bfs()
{
priority_queue<Point>que;
Point cur,next;
int i;
map[start.x][start.y]=‘#‘;
que.push(start);
while(!que.empty()){
cur=que.top();//由优先队列自动完成出队时间最少的元素
que.pop();
for(i=0;i<4;i++){
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
next.t=cur.t+1;
if(next.x<0||next.x>=n||next.y<0||next.y>=m)
continue;
if(map[next.x][next.y]==‘#‘)
continue;
if(map[next.x][next.y]==‘r‘)
return next.t;
if(map[next.x][next.y]==‘.‘){
map[next.x][next.y]=‘#‘;
que.push(next);
}
else if(map[next.x][next.y]==‘x‘){
map[next.x][next.y]=‘#‘;
next.t++;
que.push(next);
}
}
}
return -1;
}
int main()
{
int i,ans;
char *p;
while(scanf("%d%d",&n,&m)!=-1){
for(i=0;i<n;i++){
scanf("%s",map[i]);
if(p=strchr(map[i],‘a‘)){
start.x=i;
start.y=p-map[i];
start.t=0;
}
}
ans=bfs();
printf(ans+1?"%d\n":"Poor ANGEL has to stay in the prison all his life.\n",ans);
}
return 0;
}
2、http://acm.hdu.edu.cn/showproblem.php?pid=1053
题意:给出一行字符串,求出其原编码需要的编码长度和哈夫曼编码所需的长度,并求其比值
分析:根据哈夫曼生成树的生成过程可知,其生成树的权值是固定的而且这个值是最小的,而且其值根据生成树的顺序,我们可以找出规律而
不需要真的去生成一棵树然后再求出权值,其模拟过程为取出队列中权值最小的两个元素,将其值加入结果中,然后将这两个元素的权值求和
即得出其父节点的权值,将生成元素作为结点入队~~如此循环,直至取出队列中最后两个元素加入结果,实现代码如下:
view plaincopy to clipboardprint?
/*HDU 1053 采用广搜求哈夫曼生成树的权值 0ms dooder*/
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<functional>
#include<queue>
using namespace std;
#define M 1000050
char str[M];
int list[27];
priority_queue< int,vector<int>,greater<int> >que;
int main()
{
int ans,sum;
int i,a,b,c;
while(scanf("%s",str),strcmp(str,"END")){
memset(list,0,sizeof(list));
for(i=0;str[i];i++){
if(isalpha(str[i]))
list[str[i]-‘A‘]++;
else
list[26]++;
}
sum=i*8;ans=i;c=0;
for(i=0;i<27;i++){
if(list[i]){
que.push(list[i]);
c++;
}
}
if(c>1){ans=0;//注意只有一种字符的情况
while(que.size()!=1){
a=que.top();
que.pop();
b=que.top();
que.pop();
ans+=a+b;
que.push(a+b);
}
while(!que.empty())//使用后清空队列
que.pop();
}
printf("%d %d %.1f\n",sum,ans,1.0*sum/ans);
}
return 0;
}
3、http://acm.pku.edu.cn/JudgeOnline/problem?id=2263
这是第二次练习赛时,我们做过的最后一题,这里采用优先队列进行实现,在《谁说不能这样做题》中已提到这种方法,在这里再次放出代
码,~
题意:给出各城市间道路的限制载重量,求出从一个城市到另外一个城市的贷车能够运载的最大货物重量。
分析:采用优先队列,每次取出当前队列中结点的minheavy最大值出队,对它的连接结点搜索入队,这样,从出发点开始就可以
在到达终点时求出结果,即最大载货物重,实现代码如下:
view plaincopy to clipboardprint?
/*POJ 2263 16ms dooder*/
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define M 201
typedef struct w{
int city;
int mintons;
bool operator < (const w &a)const {
return mintons < a.mintons;
}//优先性定义
}Way;
char citys[M][31];
int map[M][M];
bool mark[M][M];
int n,m,from,to,ans,k;
priority_queue <Way> que;
int min(int a,int b)
{
return a>b?b:a;
}
void bfs()
{
Way cur,next;
int i;
while(!que.empty()){
cur=que.top();
que.pop();
if(cur.city==to){
if(cur.mintons>ans)
ans=cur.mintons;
while(!que.empty())
que.pop();
return ;
}
for(i=0;i<n;i++){
if(map[cur.city][i]&&!mark[cur.city][i]){
next.city=i;
next.mintons=min(cur.mintons,map[cur.city][i]);
mark[cur.city][i]=mark[i][cur.city]=1;
que.push(next);
}
}
}
}
void run()
{
int i,temp,index;
Way cur;
ans=0;
memset(mark,0,sizeof(mark));
temp=0;
for(i=0;i<n;i++){
if(map[from][i]>temp){
temp=map[from][i];
index=i;
}
}
cur.city=index;
cur.mintons=temp;
que.push(cur);
bfs();
}
int main()
{
int k1,k2,tons,t=1;
char s1[31],s2[31];
while(scanf("%d%d",&n,&m),n||m){
k=0;
while(m--){
scanf("%s%s%d",s1,s2,&tons);
for(k1=0;strcmp(s1,citys[k1])&&k1<k;k1++);
if(k1==k)
strcpy(citys[k++],s1);
for(k2=0;strcmp(s2,citys[k2])&&k2<k;k2++);
if(k2==k)
strcpy(citys[k++],s2);
map[k1][k2]=map[k2][k1]=tons;
}
scanf("%s%s",s1,s2);
for(from=0;strcmp(citys[from],s1);from++);
for(to=0;strcmp(citys[to],s2);to++);
run();
printf("Scenario #%d\n",t++);
printf("%d tons\n\n",ans);
}
return 0;
}
当然了,优先队列的用法决不是仅仅提到的这些,各种应用还需要大家去发现,给道题大家可以练习一下hdu 2066\
相信大家已经学到不少了,还有一点可以告诉大家,优先队列是启发式搜索的数据结构基础,希望好好理解,并逐步掌握其用法~
加:失策啊,竟然忘了说优先队列的效率了,其时间复杂度为O(logn).n为队列中元素的个数,存取都需要消耗时间~
旋转卡壳算法 求
N个点对的最远距离 (O n)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int Inf=(1<<31)-1;
const int M=1e5+10;
int n;
struct Point
{
int x,y;
Point(int x=0,int y=0):x(x),y(y) {}
} p[M],ch[M];
double Cross(Point a,Point b) //向量的叉积
{
return a.x*b.y-a.y*b.x;
}
bool operator <(const Point &a,const Point &b)
{
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
Point operator -(Point a,Point b)
{
return Point (a.x-b.x,a.y-b.y);
}
int ConvexHull(Point *p,int n,Point *ch)//输入点数组p,个数为n,输出点的存放数组ch
{
sort(p,p+n);//排序,按x优先,y次之的由小到大排序
int m=0;
for(int i=0; i<n; i++)
{
while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<0)m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-2; i>=0; i--)
{
while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<0)m--;
ch[m++]=p[i];
}
if(n>1)m--;
return m;//返回值是凸包的个数(点的个数);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int i,j,T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=0; i<n; i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
}
int len=ConvexHull(p,n,ch);
int maxi=-1;
for(i=0 ; i<len-1; i++)
{
for(j = i+1; j<len ; j++)
{
int x=ch[i].x - ch[j].x;
int y=ch[i].y - ch[j].y;
maxi=max(x*x+y*y,maxi);
}
}
printf("%d\n",maxi);
}
return 0;
}
时间限制:1000 ms | 内存限制:65535 KB
难度:2
描述
小蚂蚁童鞋最近迷上了位运算,他感觉位运算非常神奇。不过他最近遇到了一个难题:
给定一个区间[a,b],在区间里寻找两个数x和y,使得x异或y最大。来,帮帮他吧!
输入
有多组测试数据(以EOF结尾)。
每组数据输入两个数a,b.(0<=a<b<2^63)
输出
输出a到b之间,异或最大的值。
样例输入
1 28 9
样例输出
31
来源
上传者
(1)
#include<stdio.h>
int main()
{
int cnt;
long long n,m;
while(~scanf("%lld%lld",&n,&m))
{
m^=n;
cnt=0;
while(m)
{
cnt++;
m>>=1;
}
long long ans=1;
while(cnt--)
ans*=2;
printf("%lld\n",ans-1);
}
}
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
下雨了,下雨了,蚂蚁搬家了。
已知有n种食材需要搬走,这些食材从1到n依次排成了一个圈。小蚂蚁对每种食材都有一个喜爱程度值Vi,当然,如果Vi小于0的时候,表示蚂蚁讨厌这种食材。因为马上就要下雨了,所以蚂蚁只能搬一次,但是能够搬走连续一段的食材。时间紧急,你快帮帮小蚂蚁吧,让它搬走的食材喜爱值和最大。
输入
有多组测试数据(以EOF结尾)。
每组数据有两行,第一行有一个n,表示有n种食材排成了一个圈。(1 <= n<= 50000)
第二行分别有n个数,代表蚂蚁对第n种食材的喜爱值Vi。(-10^9 <= Vi <= 10^9)
输出
输出小蚂蚁能够搬走的食材的喜爱值总和的最大。
样例输入
33 -1 25-8 5 -1 3 -9
样例输出
57
来源
上传者
/*其实它只是在原来的情况上多加了一种首位相接情况,
所以只需不管首位想接先求出最大和ans,然后求出首位想接情况的最大和ans1
,取两者的最大值即可。ans1的求法其实和ans的求法差不多,
试想一下一个环,你要是求得了 不首尾相接的最小和 ,
那么剩下的数就是首尾相接的最大和!!!
所以ans1=所有元素的和-不首尾相接的最小和。*/
(2)
#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
long long a[55000];
int main()
{
int n;
while(cin>>n)
{
long long sum=0;
for(int i=0; i<n; i++)
{
cin>>a[i];
sum+=a[i];
}
long long need =0;
long long maxsum=0;
for(int i=0; i<n; i++)
{
need+=a[i];
if(need>maxsum) maxsum=need;
if(need<0)
need=0;
}
// cout<<"**"<<maxsum<<endl;
long long nned = 0;
long long minsum=0;
for(int i=0; i<n; i++)
{
nned+=a[i];
if(nned<minsum) minsum=nned;
if(nned>0)
nned = 0;
}
// cout<<minsum<<"*-*"<<endl;
if(maxsum>sum-minsum)
cout<<maxsum<<endl;
else
cout<<(sum-minsum)<<endl;
}
}
时间限制:2000 ms | 内存限制:65535 KB
难度:4
描述
蚂蚁终于把尽可能多的食材都搬回家了,现在开始了大厨计划。
已知一共有 n 件食材,每件食材有一个美味度 Ai 和新鲜度 Bi , 如果蚂蚁在第t时刻将第i样食材烹饪成功,则得到Ai-t*Bi 的美味指数,当然,用第i件食材做饭要花去 Ci 的时间。
众所周知,蚂蚁的厨艺不怎么样,所以他需要你设计做饭方案使得在时间 T 内完成的美味指数最大。
输入
有多组测试数据。
第一行是两个正整数,表示蚂蚁的做饭时间T和食材个数n。(n<=50, 1<=T<=100000)。
接下来n行,每行有三个数,Ai,Bi,Ci。分别代表美味度、新鲜度和用该食材做饭花费的时间。(0<Ai,Bi,Ci<=100000).
输出
输出一个数字,表示最大美味指数
样例输入
6 1200 5 1
样例输出
195
来源
上传者
(3)
#include<iostream>
#include<string.h>
#include<cstdio>
#include<algorithm>
using namespace std;
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
struct ant
{
int a,b,t;
} p[100005];
int cmp(ant x, ant y)
{
return x.b*y.t > x.t*y.b;
}
int dp[100005];
int main()
{
int n,T;
while(cin>>T>>n)
{
memset(dp,0,sizeof(dp));
for(int i=0; i<n; i++)
cin>>p[i].a>>p[i].b>>p[i].t;
sort(p,p+n,cmp);
int sum=0;
for(int i=0; i<n; i++)
{
for(int j=min(T,p[i].a/p[i].b); j>=p[i].t; j--)
{
dp[j]=max(dp[j],dp[j-p[i].t]+p[i].a-p[i].b*j);
if(dp[j]>sum)
sum=dp[j];
}
}
cout<<sum<<endl;
}
}
(4)
时间限制:1000 ms | 内存限制:65535 KB
难度:5
描述
蚂蚁终于把食材制作成 “美味”的食品了, 现在他邀请他的小伙伴PIAOYI帮他试吃。
蚂蚁共制作了n个食品,PIAOYI会选择试吃连续 S~T 个食品(最少连续吃S个,最多吃T个) 然后按照美味程度给每个食品评价一个美味指数Ai。蚂蚁非常了解PIAOYI,所以他能够猜出PIAOYI对每个食品的评价,所以他想请PIAOYI从某一个食品开始试吃,使得得到的美味指数平均值最大。
输入
有多组测试数据。
对于每组测试数据,第一行分别为n,S,T.(0<n<100000, 0<S <= T < n-S )
接下来一行输入n个数Ai,分别表示食品的美味指数.(-10000<Ai<10000)
输出
输出最大的美味指数平均值,保留三位小数。
样例输入
3 2 23 -1 2
样例输出
1.000
来源
上传者
#include <cstdio>
#define N 100010
using namespace std;
int n, s, t;
double ans;
double a[N], sum[N];
int b[N], q[N];
bool check(double x){
int l = 1, r = 0;
sum[0] = 0;
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + (double)b[i] - x;
for (int i = 1; i <= n; i++)
{
if (i >= s)
{
while ( l <= r && sum[i-s] < sum[q[r]])
r--;
q[++r] = i-s;
}
if ( l <= r && q[l] < i-t )
l++;
if ( l <= r && sum[i] - sum[q[l]] >= 0)
return true;
}
return false;
}
int main()
{
while( ~scanf("%d%d%d", &n, &s, &t))
{
double l, r, mid;
for(int i = 1; i <= n; i++)
scanf("%d", &b[i]);
ans = l = -10000; r = 10000;
while ( r-l > 1e-5)
{
mid = (l + r) / 2;
if (check(mid))
ans = l = mid;
else r = mid;
}
printf("%.3lf\n", ans);
}
return 0;
}
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
PIAOYI在对蚂蚁制做的"美味"试吃之后,作出了一个非常低的评价,蚂蚁很难过.于是蚂蚁开始发愤图强,苦练烹饪技术。
已知有 N 种食品,分别编号1~N,蚂蚁每次练习时,会先随机出一个数 x, 然后把 N 以内编号为x的倍数的食品都练习一遍,所以这些食品的熟练度也会增加 y。不过在苦练一段时间后,他就想查看一下自己的水平,他会随机一个数 j,然后查看第 j 种食品的熟练度。然后再接着苦练......
输入
有多组测试数据。
对于每组数据:
第一行,有两个数N,M(N<1000000, M<100000)分别代表食品的种类数 和 蚂蚁苦练和查询的总次数。
第二行,有N个数Ai( 0<Ai< 10000 )分别代表蚂蚁对每种食品的初始熟练度。
接下来有M行,表示蚂蚁的M个操作。
操作1格式为1 x y(0<x<=N, 0< y <10000)代表蚂蚁在苦练, x的倍数都会增加熟练度y。
操作2格式为2 j(j <= N)则是查询第j种食品的熟练度。
PS:(操作2 次数小于10000)。
输出
对于每次查询,输出对应食品的熟练度。
样例输入
5 46 9 9 8 1 2 41 2 51 3 12 4
样例输出
813
来源
上传者
(5)
#include<stdio.h>
#include<string.h>
#include<math.h>
const int M=1e6+5;
int num[M];
int add[M];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(add,0,sizeof(add));
for(int i=1; i<=n; i++)
scanf("%d",&num[i]);
while(m--)
{
int t ;
scanf("%d",&t);
if(t==1)
{
int x,y;
scanf("%d%d",&x,&y);
add[x]+=y;
}
else
{
int j;
scanf("%d",&j);
int res=num[j];
int s=(int)sqrt((double)j);
for(int i=1; i<=s; i++)
if(j%i==0)
res+=add[i]+add[j/i];
if(s*s==j)
res-=add[s];
printf("%d\n",res);
}
}
}
return 0;
}
时间限制:1000 ms | 内存限制:65535 KB
难度:5
描述
经过一系列的训练,蚂蚁的烹饪手艺终于可以见人了。
他烹饪了n盘食品,编号1~n,每一盘都有一个美味价值Ai。现在他要选取不超过 k 盘并且任意两盘编号不能够相邻,送给好朋友PIAOYI品尝。因为上次的“试吃”事件让PIAOYI很不开心,所以蚂蚁决定选取足够大的美味价值来向PIAOYI道歉。但是蚂蚁又不知道该选那些食品,请你帮帮他吧?
输入
有多组测试数据。
对于每组测试数:
第一行有两个数n,k(n<=100000, k <= n/2)分别代表蚂蚁烹饪了n盘食品,最多选取k盘.
第二行有n个数字 Ai (|Ai| <= 1000000)表示每一盘食品的美味价值。
输出
对于每组数据,输出蚂蚁能够选取的最大值。
样例输入
6 3 100 1 -1 100 1 -1
样例输出
200
来源
上传者
(6)
#include<iostream>
#include <cstdio>
#include<cstring>
#include<queue>
#define maxn 1000001
using namespace std;
long long l[maxn],r[maxn],x[maxn];
(6)bool vis[maxn];
struct data
{
long long v,num;
friend bool operator < (data a,data b){
return a.v<b.v;
}
};
data now;
int main()
{
int n,m;
while(cin>>n>>m)
{
memset(vis, 0, sizeof(vis));
priority_queue<data>que;
long long ans=0;
for(int i=1;i<=n;l[i]=i-1,r[i]=i+1,i++)
{
scanf("%lld",&x[i]);
now.num=i;
now.v=x[i];
que.push(now);
}
l[1]=1,r[n]=n;
for(int i=1;i<=m;i++){
now=que.top();
que.pop();
while(vis[now.num]){
now=que.top();
que.pop();
}
if(now.v<0)break;
ans+=now.v;
vis[l[now.num]]=vis[r[now.num]]=1;
x[now.num]=x[l[now.num]]+x[r[now.num]]-x[now.num];
l[now.num]=l[l[now.num]];
r[now.num]=r[r[now.num]];
if(now.num!=1)r[l[now.num]]=now.num;
if(now.num!=n)l[r[now.num]]=now.num;
now.v=x[now.num];
que.push(now);
}
cout<<ans<<endl;
}
return 0;
}
(7)
时间限制:2000 ms | 内存限制:65535 KB
难度:4
描述
蚂蚁做了一个梦,梦到自己穿越到了一个森林。
蚂蚁进入到了一片丛林,结果他发现有n只怪物排成一排站在他面前。
蚂蚁有一杆火枪能对付这些怪物。他知道从左至右数第i只怪物的血量是mi。现在蚂蚁可以将一些子弹射向某个怪物。蚂蚁可以控制他所发射的子弹数量及子弹的威力值。当某个子弹射到第i个怪物,如果这个子弹的威力值为p,除了这个怪物会掉p点血以外,它左边的第j个怪物(j<i),也会遭到Max(0, p - (i - j) * (i - j))的溅射伤害(好神奇的子弹)。当某只怪物的血量小于0时,它就死了,但它的尸体还在,即怪物的位置永远不会改变。蚂蚁希望只用k发子弹,请你求出一个最小的正整数p,使蚂蚁用k发子弹且每发子弹的威力值为p就可以消灭所有怪物。
输入
有多组测试数据。
对于测试数据:
第一行有一个n k分别代表怪物的数量,和蚂蚁的子弹数。(n<=500000,k<=500000).
第二行有n个数,分别代表每个怪物的血量mi(1<=mi<=10^10).
输出
输出子弹的威力值
样例输入
3 11 4 5
样例输出
6
提示
大于10W的数据只有一组
来源
上传者
(7)
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
int arr[4000000];
const int Mx = 5e5+50;
LL n, k;
LL Mi[Mx], Num[Mx];
bool check( LL p )
{
LL tmp = 0, dat = 0;
LL L = int(sqrt(p));
LL l = 1, r = 0;
for(LL i = 1; i <= n; i++ )
{
while( l <= r && Num[l] + L < i)
{
tmp -= p-L*L ;
dat -= 2*L + 1;
l++;
}
tmp -= dat;
dat += (r-l +1)*2;
while( tmp <= Mi[i] )
{
Num[++r] = i;
if( r > k) return false;
tmp += p;
dat += 1;
}
}
return true;
}
int main()
{
while( ~scanf( "%d%d", &n, &k))
{
for(int i = 1; i <= n; i++)
scanf( "%lld", &Mi[n-i+1] );
LL l = 1LL, r = (LL)1e11;
while(l < r)
{
LL mid = (l+r)/2;
if( check(mid) ) r = mid;
else l = mid+1;
}
cout << l << endl;
}
return 0;
}
时间限制:2000 ms | 内存限制:65535 KB
难度:5
描述
蚂蚁是一个古玩爱好者,他收藏了很多瓶瓶罐罐。
有一天,他要将他的宝贝们一字排开, 摆放到一个长度为L的展台上。
已知他有n件宝贝, 每件宝贝的宽为w,由于这些瓶瓶罐罐的形状特殊,所以在摆放时需要至少X的宽度来摆放他们,(仅摆放时需要X的宽度, 摆放后宽度仍为w)现在已知了每件宝贝的宽度wi,和摆放它们所需的宽度Xi。请你帮蚂蚁计算一下,在这个展台上,他最多能摆多宽的宝贝。
输入
有多组测试数据。
对于每一组测试数据:
第一行: n L 分别代表有n件宝贝,展台长度为L;(n<1000, L<10000)
接下来有n行, 每行有两个整数 wi xi 分别代表第i件宝贝的宽度和摆放时需要的宽度。(0<wi <= xi < 10000).
输出
输出蚂蚁能够摆出的最大的宽度。
样例输入
3 102 33 44 7
样例输出
9
提示
蚂蚁的难题大结局,祝大家水题开心,天天AC!
来源
上传者
(8)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 10000 + 10;
struct Info
{
int w, x;
}sa[1010];
int dp[maxn];
int cmp(Info a, Info b)
{
return a.w+b.x > a.x+b.w;
}
int main()
{
int n, L;
while(~scanf("%d%d", &n, &L))
{
for(int i = 1; i <= n; i++)
scanf("%d%d", &sa[i].w, &sa[i].x);
sort(sa+1, sa+n+1, cmp);
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
for(int j = L; j-sa[i].x >= 0; j--)
dp[j] = max(dp[j], dp[j-sa[i].w]+sa[i].w);
printf("%d\n", dp[L]);
}
return 0;
}
多重背包:
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N = 1005;
int dp[N];
int c[N],w[N],num[N];
int n,m;
void ZeroOne_Pack(int cost,int weight,int n)
{
for(int i=n; i>=cost; i--)
dp[i] = max(dp[i],dp[i-cost] + weight);
}
void Complete_Pack(int cost,int weight,int n)
{
for(int i=cost; i<=n; i++)
dp[i] = max(dp[i],dp[i-cost] + weight);
}
int Multi_Pack(int c[],int w[],int num[],int n,int m)
{
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
if(num[i]*c[i] > m)
Complete_Pack(c[i],w[i],m);
else
{
int k = 1;
while(k < num[i])
{
ZeroOne_Pack(k*c[i],k*w[i],m);
num[i] -= k;
k <<= 1;
}
ZeroOne_Pack(num[i]*c[i],num[i]*w[i],m);
}
}
return dp[m];
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>m>>n;
for(int i=1; i<=n; i++)
cin>>c[i]>>w[i]>>num[i];
cout<<Multi_Pack(c,w,num,n,m)<<endl;
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:acm模板
原文地址:http://blog.csdn.net/u012349696/article/details/48142327