题意:有n个会议,对于会议i,它将花费时间ci,并需要在进行前先完成指定的di个会议。在每个会议中,将为在它之前进行的每个会议各花费1个单位的时间。现在要为这n个会议进行排序,使得其中进行时间最长的会议时间最短。
思路:从每个会议进行前需要完成若干个指定会议这一点可以看出,
可以在(会议i)<--(会议i进行前需要进行的会议)之间连有向边,使用拓扑排序就可求出会议进行顺序。
对于第i个进行的会议,它的时长为c+i。
粗略地想,我们应当选择当前能够进行并且时间最长的会议,
于是想到使用优先队列,在拓扑排序过程中,将ci值大的先取出进行删边。
但是仔细一想,这种贪心没有考虑到当前不满足进行条件但时间很长的会议。
于是先使用dfs,求出所有需要先进行会议i的(cj+(会议i与会议j的距离))的最大值dis[i],将dis值大的先取出进行删边。
(具体看代码)
。。看了一圈题解,发现只要反向建边就可以直接拓扑了。啊这。。
#include<cstdio> #include<queue> #include<algorithm> using namespace std; const int maxn=400005; struct node { int id,dis,t; node() {} node(int a,int b,int c) { id=a; dis=b; t=c; } bool operator < (const node &b) const { return dis<b.dis; } }; priority_queue<node>q; int n,a[maxn],in[maxn],last[maxn],num; int dis[maxn],vis[maxn],ans; struct edge { int to,nxt; }e[maxn]; void add(int x,int y) { e[++num].to=y; e[num].nxt=last[x]; last[x]=num; } int topo() { for (int i=1;i<=n;i++) if (!in[i]) q.push(node(i,dis[i],a[i])); int now=0,ans=0; node x; while (!q.empty()) { x=q.top(); q.pop(); ans=max(ans,now+x.t); now++; for (int i=last[x.id];i;i=e[i].nxt) { in[e[i].to]--; if (in[e[i].to]==0) q.push(node(e[i].to,dis[e[i].to],a[e[i].to])); } } return ans; } void dfs(int x) { vis[x]=1; dis[x]=a[x]; for (int i=last[x];i;i=e[i].nxt) { if (!vis[e[i].to]) dfs(e[i].to); dis[x]=max(dis[x],dis[e[i].to]+1); } } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d%d",&a[i],&in[i]); for (int j=1,u;j<=in[i];j++) { scanf("%d",&u); add(u,i); } } for (int i=1;i<=n;i++) if (!in[i]) dfs(i); printf("%d ",topo()); return 0; }
G
题意:有一个n*n的迷宫,迷宫中有若干个方块。球从某个起点开始,要最终走到终点(0,0)。每次操作可以走上下左右四个方向,直至碰到方块或者边界球才停止。现在给出一串操作,要求设计球的起点和迷宫中方块的分布,使得球能够根据这串操作走至终点。
思路:一开始想着从终点开始倒着做,发现很难想。看了别人的代码,发现直接正着做会好做一点。
()
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; vector<pair<int,int> >a; int dir[100]; char s[25]; int main() { int i,x=0,y=0,len,r=1;//先假装起点为0,0 scanf("%s",s); dir['R']=dir['L']=1; dir['U']=dir['D']=2; len=strlen(s); if (len>=3 && s[len-1]==s[len-3] && dir[s[len-1]]==dir[s[len-2]]) { printf("impossible "); return 0; } for (i=0;i<len;i++) { if (i<len-1 && dir[s[i]]!=dir[s[i-1]]) r++; if (s[i]=='R') { x=r; a.push_back({x+1,y}); } else if (s[i]=='L') { x=-r; a.push_back({x-1,y}); } else if (s[i]=='U') { y=r; a.push_back({x,y+1}); } else if (s[i]=='D') { y=-r; a.push_back({x,y-1}); } } for (i=0;i<a.size();i++) { a[i].first-=x; a[i].second-=y; } sort(a.begin(),a.end()); a.erase(unique(a.begin(),a.end()),a.end());//去重 printf("%d %d ",-x,-y);//根据终点为0,0,修改起点坐标为0-x,0-y printf("%d ",a.size()); for (i=0;i<a.size();i++) printf("%d %d ",a[i].first,a[i].second); return 0; }
题意:有n个气球,容量从1到n,同时有n个气瓶,有a[i]容量的气。当给气球充气的气瓶的容量大于气球的,那么气球就会爆炸,
找出一种气球与气瓶的配对,使得没有气球爆炸并且所有配对中a[i]/i的最小值最大,输出这个最小值。
思路:直接将a排序,然后两两配对就行了。
注意答案直接输出就行了,special judge
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=200005; int a[maxn]; int main() { int i,n,flag; double ans,tmp; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); ans=1.0; flag=0; for (i=1;i<=n;i++) { if (a[i]>i) { flag=1; break; } else { tmp=(double)a[i]/i; ans=min(ans,tmp); } } if (!flag) printf("%lf ",ans); else printf("-1 "); return 0; }