A-CF-195A
我是傻逼
仔细看题
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=507;
const int inf=0x3f3f3f3f;
const int MOD=1e9+7;
int x,y,z;
int main()
{
scanf("%d %d %d",&x,&y,&z);
double sum=((double)x*z)/(double)y-z;
if(((int)sum+z)*y>=x*z)//开始把获胜人搞反了
printf("%d\n",(int)sum);
else printf("%d\n",(int)sum+1);
return 0;
}
B-HDU-4081
开始以为是最优比例生成树,没推出表达式就跳过了,
实际上是最小生成树的变形,
首先根据点建边,然后建立最小生成树,再遍历树上父亲节点,一个一个删除判断,找到
(删除边后的两棵树上各自最大的顶点权重和) / (除删除边外所有边权重和) 的最大值即可
附思路博客
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=1007;
const int inf=0x3f3f3f3f;
const int MOD=1e9+7;
int n;
struct node
{
int x,y,z;
}dingdian[maxn];
double mp[maxn][maxn];
double dis[maxn];
bool vis[maxn];
int father[maxn];
double len(node a,node b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double prime()
{
memset(dis,inf,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(father,0,sizeof(father));
double ans=0;
dis[1]=0;
vis[1]=true;
for(int i=1;i<=n;i++)
{
dis[i]=mp[1][i];
father[i]=1;
}
for(int i=2;i<=n;i++)
{
double minn=inf;
int k=0;
for(int j=1;j<=n;j++)
{
if(vis[j]==false&&minn>dis[j])
{
minn=dis[j];
k=j;
}
}
vis[k]=true;
ans+=minn;
for(int j=1;j<=n;j++)
{
if(vis[j]==0&&dis[j]>mp[k][j])
{
dis[j]=mp[k][j];
father[j]=k;
}
}
}
return ans;
}
int max_1,max_2;
int FIND(int x,int y,int z)//当前节点和两棵树的根节点
{
if(x==y)
{
if(max_1<dingdian[x].z) max_1=dingdian[x].z;
return 1;
}
if(x==z)
{
if(max_2<dingdian[x].z) max_2=dingdian[x].z;
return 0;
}
if(FIND(father[x],y,z)==1)
{
if(max_1<dingdian[x].z) max_1=dingdian[x].z;
return 1;
}
else
{
if(max_2<dingdian[x].z) max_2=dingdian[x].z;
return 0;
}
}
int FIND_1(int y)//求y的根节点
{
return y==father[y]?y:FIND_1(father[y]);
}
double solve(int x,int y)//i,father[i]
{
max_1=max_2=0;
int tmp=father[x];
father[x]=x;
y=FIND_1(y);
for(int i=1;i<=n;i++)
{
FIND(i,x,y);
}
father[x]=tmp;
return max_1+max_2;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d",&dingdian[i].x,&dingdian[i].y,&dingdian[i].z);
}
for(int i=1;i<=n;i++)
{
mp[i][i]=0;
for(int j=1+i;j<=n;j++)
{
mp[i][j]=mp[j][i]=len(dingdian[i],dingdian[j]);
}
}
double sum1=prime();
double ans=0;
for(int i=1;i<=n;i++)
{
ans=max(ans,solve(i,father[i])/(sum1-mp[father[i]][i]));
}
printf("%.2f\n",ans);
}
return 0;
}
C-POJ-3295
SPFA。。。一直没搞懂,先放一放
学长贴的标程
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
struct edge
{
int u,v,w,next;
};
edge e[10050];
const int INF=0x3f3f3f3f;
int dis[10050],head[10050],cnt;
int n,m,w;
int vis[10050],num[10050];
void add(int u,int v,int w)
{
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt++;
}
bool spfa()
{
fill(vis,vis+10050,0);
fill(num,num+10050,0);
fill(dis,dis+10050,INF);
queue<int> q;
dis[1]=0;
q.push(1);
num[1]++;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=e[i].next){
int v=e[i].v;
if(dis[v]>dis[x]+e[i].w){
dis[v]=dis[x]+e[i].w;
if(vis[v]==0){
vis[v]=1;
num[v]++;
q.push(v);
if(num[v]>=n){
return true;
}
}
}
}
}
return false;
}
int main()
{
int t;
cin>>t;
while(t--){
cnt=0;
fill(head,head+10050,-1);
scanf("%d %d %d",&n,&m,&w);
for(int i=0;i<m;i++){
int u,v,s;
cin>>u>>v>>s;
add(u,v,s);
add(v,u,s);
}
for(int i=0;i<w;i++){
int u,v,s;
cin>>u>>v>>s;
add(u,v,-s);
}
if(spfa()){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
return 0;
}
D-POJ-1679
prime求最小生成树,
首先跑prime记录父亲节点和最小距离,再根据父亲节点一个一个删边重新跑prime,判断是否有相同值即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=107;
const int inf=0x3f3f3f3f;
const int MOD=1e9+7;
int n,m;
int mp[maxn][maxn];
int dis[maxn];
bool vis[maxn];
int father[maxn];
int prime1()
{
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
int ans=0;
vis[1]=true;
father[1]=0;
for(int i=1;i<=n;i++)
{
dis[i]=mp[1][i];
father[i]=1;
}
for(int point=2;point<=n;point++)
{
int minn=inf,k=0;
for(int i=1;i<=n;i++)
if(vis[i]==false&&minn>dis[i])
{
minn=dis[i];
k=i;
}
vis[k]=true;
ans+=minn;
for(int i=1;i<=n;i++)
{
if(dis[i]>mp[k][i])
{
dis[i]=mp[k][i];
father[i]=k;
}
}
}
return ans;
}
int prime()
{
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
int ans=0;
vis[1]=true;
// father[1]=0;
for(int i=1;i<=n;i++)
{
dis[i]=mp[1][i];
// father[i]=1;
}
for(int point=2;point<=n;point++)
{
int minn=inf,k=0;
for(int i=1;i<=n;i++)
if(vis[i]==false&&minn>dis[i])
{
minn=dis[i];
k=i;
}
vis[k]=true;
ans+=minn;
for(int i=1;i<=n;i++)
{
if(dis[i]>mp[k][i])
{
dis[i]=mp[k][i];
// father[i]=k;
}
}
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(mp,inf,sizeof(mp));
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
mp[a][b]=mp[b][a]=c;
}
int ans=prime1();
bool flag=1;
for(int i=1;i<=n;i++)
if(mp[i][father[i]]!=inf)
{
int tmp=mp[i][father[i]];
mp[i][father[i]]=mp[father[i]][i]=inf;
if(ans==prime())
{
flag=0;
}
mp[i][father[i]]=mp[father[i]][i]=tmp;
}
if(flag) printf("%d\n",ans);
else printf("Not Unique!\n");
}
}
E-POJ-1511
正反记录路径,跑两次dij,第一次代表从1出发到其余点的最短路,第二次表示其余点回到1的最短路
最好是用链式前向星建边,我用vector建边TLE了无数次,赛后看大佬ac代码用memset对vector清零才刚好卡着8000ms水过。。。
8000ms代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
const int inf=0x3f3f3f3f;
const int MOD=1e9+7;
int n,m;
int dis[maxn];
int dis1[maxn];
//int father[maxn];
bool vis[maxn];
struct node
{
int to,val;
node (int a,int b):to(a),val(b){}
friend bool operator < (node a,node b)
{
return a.val>b.val;
}
};
vector<node> v[maxn];
vector<node> v1[maxn];
void dij(int s)
{
priority_queue <node> q;
for( int i=1;i<=n;i++) vis[i]=false,dis[i]=inf;
dis[s]=0;
q.push(node(s,0));
while(!q.empty())
{
node tmp=q.top();
q.pop();
if(vis[tmp.to]) continue;
vis[tmp.to]=true;
for(int i=0;i<(int) v[tmp.to].size();i++)
{
int to=v[tmp.to][i].to;
int val=v[tmp.to][i].val;
if(vis[to]==false&&dis[to]>dis[tmp.to]+val)
{
dis[to]=dis[tmp.to]+val;
q.push(node(to,dis[to]));
}
}
}
}
void dij1(int s)
{
for( int i=1;i<=n;i++) vis[i]=false,dis1[i]=inf;
priority_queue <node> q;
dis1[s]=0;
q.push(node(s,0));
while(!q.empty())
{
node tmp=q.top();
q.pop();
if(vis[tmp.to]) continue;
vis[tmp.to]=true;
for(int i=0;i<(int) v1[tmp.to].size();i++)
{
int to=v1[tmp.to][i].to;
int val=v1[tmp.to][i].val;
if(vis[to]==false&&dis1[to]>dis1[tmp.to]+val)
{
dis1[to]=dis1[tmp.to]+val;
q.push(node(to,dis1[to]));
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(v,0,sizeof v);
memset(v1,0,sizeof v1);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
v[a].push_back(node(b,c));
v1[b].push_back(node(a,c));
}
dij(1);
dij1(1);
__int64 ans=0;
for(int i=1;i<=n;i++)
{
ans=ans+dis[i]+dis1[i];
}
printf("%I64d\n",ans);
}
return 0;
}
F-CF-371C
学姐改题面改错了…
二分查找答案
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <functional>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
const int inf=0x3f3f3f3f;
const int MOD=1e9+7;
const ll it=1e12;
char st[107];
ll s,b,c;//需要
ll ss,bb,cc;//家里有
ll sss,bbb,ccc;//价格
ll res;
bool check(ll x)
{
ll need=0;
if(b*x>bb) need+=(b*x-bb)*bbb;
if(s*x>ss) need+=(s*x-ss)*sss;
if(c*x>cc) need+=(c*x-cc)*ccc;
if(need<=res) return true;
else return false;
}
int main()
{
s=b=c=0;
scanf("%s",st);
for(int i=0;i<strlen(st);i++)
{
if(st[i]=='B') b++;
else if(st[i]=='C') c++;
else if(st[i]=='S') s++;
}
scanf("%lld %lld %lld",&bb,&ss,&cc);
scanf("%lld %lld %lld",&bbb,&sss,&ccc);
scanf("%lld",&res);
ll l=0,r=2*it,mid,ans;
while(l<r)
{
mid=(l+r)/2;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else r=mid;
}
printf("%lld\n",ans);
return 0;
}
赛况记录:
A - WA5次(我是傻逼);
B - 未完成;
C - 未完成;
D - AC;
E - 未完成(链式前向星) ;
F - 未完成 ;
附contest链接