只想到一种情况 另外一种情况是参考别人的
2个人为一轮
a b c d
a b 去 a 回 c d 去 b 回(最小的2个去 2个在回来 。。。)
其实还有一种
a b 去 a 回 a c 去 a 回(只是最小的来回)
2中情况要具体分析 不能全是第一种 全是第二种 每2个2个人取小值
这个真不会
语言: C++ 用户:614173971 提交时间 : 2014-01-15 16:33:33.0
#include <cstdio>
#include <algorithm>
using namespace std;
const __int64 MAX = 100010;
__int64 a[MAX];
int main()
{
__int64 n;
__int64 i;
while(~scanf("%I64d",&n))
{
for(i = 1;i <= n; i++)
scanf("%I64d",&a[i]);
if(n == 0)
{
printf("%0\n");
continue;
}
if(n == 1)
{
printf("%I64d\n",a[1]);
continue;
}
sort(a+1,a+n+1);
__int64 sum = 0;
for(i = n; i >= 4; i -= 2)
sum += min(2 * a[1] + a[i] + a[i-1],a[1] + 2 * a[2] + a[i]);
if(n%2 == 0)
sum += a[2];
else
sum += a[1] + a[2] + a[3];
printf("%I64d\n",sum);
}
return 0;
}
这题是看书学习的 据说是经典题 黑书上有讲 转换成点是否在三角形内 三维的叉积 点积
好题
#include <cstring>
#include <cmath>
#include <cstdio>
const double eps = 1e-10;
struct Point3
{
double x, y, z;
Point3(double x=0, double y=0, double z=0):x(x),y(y),z(z){}
};
typedef Point3 Vector3;
Vector3 operator + (Vector3 A, Vector3 B)
{
return Vector3(A.x+B.x, A.y+B.y, A.z+B.z);
}
Vector3 operator - (Vector3 A, Vector3 B)
{
return Vector3(A.x-B.x, A.y-B.y, A.z-B.z);
}
int dcmp(double x)
{
if(fabs(x) < eps)
return 0;
else
return x < 0 ? -1 : 1;
}
double Dot(Vector3 A, Vector3 B)//点积
{
return A.x*B.x + A.y*B.y + A.z*B.z;
}
double Length(Vector3 A)//向量长度
{
return sqrt(Dot(A, A));
}
Vector3 Cross(Vector3 A, Vector3 B)//求叉积
{
return Vector3(A.y*B.z - A.z*B.y, A.z*B.x - A.x*B.z, A.x*B.y - A.y*B.x);
}
double Area(Point3 p0, Point3 p1, Point3 p2)
{
return Length(Cross(p1-p0, p2-p0));
}
bool PointInTri(Point3 p, Point3 p0, Point3 p1, Point3 p2)//判断p是否在三角形内
{
double area1 = Area(p, p0, p1);
double area2 = Area(p, p1, p2);
double area3 = Area(p, p2, p0);
if(Area(p0,p1,p2) == 0)//3个点没有成为三角形 线段或者点的情况
{
if(Dot(p0-p, p1-p) < 0)
return true;
if(Dot(p1-p, p2-p) < 0)
return true;
if(Dot(p2-p, p0-p) < 0)
return true;
return false;
}
if(dcmp(area1) == 0)//不能在三角形边上
return false;
if(dcmp(area2) == 0)
return false;
if(dcmp(area3) == 0)
return false;
return dcmp(area1 + area2 + area3 - Area(p0,p1,p2)) == 0;
}
bool ok(Point3 p, Point3 p0, Point3 p1, Point3 p2)//判断p是否在三角形所在的平面上
{
Vector3 A = Cross(p1-p0, p2-p0);
Vector3 B = p-p0;
return dcmp(Dot(A, B)) == 0;
}
int main()
{
double x,y,z;
while(scanf("%lf %lf %lf",&x,&y,&z),x||y||z)
{
Point3 p0(x,y,z);
scanf("%lf %lf %lf",&x,&y,&z);
Point3 p1(x,y,z);
scanf("%lf %lf %lf",&x,&y,&z);
Point3 p2(x,y,z);
scanf("%lf %lf %lf",&x,&y,&z);
Point3 p(x,y,z);
if(ok(p,p0,p1,p2) && PointInTri(p,p0,p1,p2))
puts("YES");
else
puts("NO");
}
return 0;
}
dijkstra 因为k最多就5个 求出k个超市到所有点的距离 然后枚举起点(除去k个点)途径k个超市 在回来 你们所以需要的条件已经通过dijkstra求出来了
只需枚举求最小值 n*2^k 加上最短路 k*nlogn
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define pii pair<int,int>
#define INF 999999999;
using namespace std;
const int MAX = 10010;
vector <pii> edge[MAX];
int ok[MAX];
int dis[10][MAX];
int ans[10];
int n,m,k;
void dijkstra(int s, int pos)
{
priority_queue <pii, vector<pii> ,greater<pii> > q;
bool vis[MAX];
for(int i = 1;i <= n; i++)
{
if(i == s)
dis[pos][i] = 0;
else
dis[pos][i] = INF;
}
memset(vis,false,sizeof(vis));
q.push(make_pair(0,s));
while(!q.empty())
{
pii u = q.top();
q.pop();
int x = u.second;
if(vis[x])
continue;
vis[x] = true;
int len = edge[x].size();
for(int i = 0; i < len; i++)
{
pii v = edge[x][i];
if(dis[pos][v.second] > dis[pos][x] + v.first)
{
dis[pos][v.second] = dis[pos][x] + v.first;
q.push(make_pair(dis[pos][v.second],v.second));
}
}
}
}
int main()
{
int i,j;
int u,v,w;
int sum = INF;
scanf("%d %d %d",&n,&m,&k);
for(i = 1;i <= k; i++)
{
scanf("%d",&j);
ans[i] = j;
ok[j] = i;
}
for(i = 1;i <= m; i++)
{
scanf("%d %d %d",&u,&v,&w);
edge[u].push_back(make_pair(w,v));
edge[v].push_back(make_pair(w,u));
}
for(i = 1; i <= k; i++)
dijkstra(ans[i],i);
for(i = 1;i <= n; i++)
{
if(ok[i])
continue;
sort(ans+1,ans+1+k);
do
{
int cnt = 0;
for(j = 1;j <= k; j++)
{
if(j == 1)
cnt += dis[ok[ans[j]]][i];
else if(j == k)
cnt += dis[ok[ans[j]]][i] + dis[ok[ans[j]]][ans[j-1]];
else
cnt += dis[ok[ans[j]]][ans[j-1]];
}
if(sum > cnt)
sum = cnt;
//printf("%d\n",cnt);
}while(next_permutation(ans+1,ans+k+1));
}
printf("%d\n",sum);
return 0;
}
找出循环节就行了 自己就是速度太慢了 简单题也写了半天
#include <cstdio>
#include <cstring>
#include <cstdio>
using namespace std;
struct node
{
int u;
int v;
}a[220][22];
int b[100000];
int mp[220][22];
int main()
{
int n,m,t,s;
int i,j,u,v;
int cnt;
while(scanf("%d %d %d %d",&m,&t,&s,&n)!=EOF)
{
cnt = 1;
memset(mp,0,sizeof(mp));
for(i = 1;i <= m; i++)
{
for(j = 1;j <= t; j++)
{
scanf("%d %d",&u,&v);
a[i][j].u = v;
a[i][j].v = u;
}
}
u = s;
v = 1;
mp[s][1] = cnt;
b[cnt++] = s;
while(1)
{
int uu = u;
int vv = v;
u = a[uu][vv].u;
v = a[uu][vv].v;
//printf(" %d %d\n",u,v);
if(cnt-1 == n)
{
printf("%d\n",b[cnt-1]);
break;
}
if(mp[u][v])
{
int k = cnt - mp[u][v];
int nn = (n - mp[u][v] + 1) % k;
if(nn == 0)
nn = k;
printf("%d\n",b[mp[u][v] - 1 + nn]);
//printf("%d\n",k);
break;
}
else
{
mp[u][v] = cnt;
b[cnt++] = u;
}
}
}
return 0;
}
我直接用了优先队列 1A 是不是数据水了啊 5s 用了340ms
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int main()
{
int n,m;
int i,x;
while(scanf("%d %d",&n,&m)!=EOF)
{
priority_queue <int> q;
for(i = 1;i <= n + m; i++)
{
scanf("%d",&x);
if(x == -1)
{
printf("%d\n",q.top());
q.pop();
}
else
q.push(x);
}
}
return 0;
}
一看是二分 开始错了2次 犯傻了
每次二分到那个位置把那个数插进去 数组很难能实现 10秒我就乱搞了 用vector insert 结果对了
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAX = 45010;
int a[MAX];
vector <int> dp;
int pos[MAX];
int main()
{
int n;
int i,j,l,r,m,len;
scanf("%d",&n);
for(i = 0;i < n; i++)
scanf("%d",&a[i]);
dp.push_back(a[0]);
pos[0] = 0;
len = 0;
for(i = 1;i < n; i++)
{
l = 0;
r = dp.size() - 1;
while(l <= r)
{
m = (l + r) >> 1;
if(a[i] < dp[m])
l = m + 1;
else
r = m - 1;
}
dp.insert(dp.begin()+l,a[i]);
pos[i] = l;
}
for(i = 0;i < n; i++)
printf("%d\n",pos[i]+1);
return 0;
}
一看题意 发现是割点 书上看到过 学了下 一下就懂了 裸的应用 可以看一下白皮书
一个dfs算法解决
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int MAX = 310;
vector <int> G[MAX];
int pre[MAX];
int low[MAX];
bool iscnt[MAX];
int n,m;
int cnt = 0;//时间戳
int dfs(int u,int fa)
{
int lowu = pre[u] = ++cnt;
int child = 0;//子节点数
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(!pre[v])
{
child++;
int lowv = dfs(v,u);
lowu = min(lowu,lowv);
if(lowv >= pre[u])
iscnt[u] = true;
}
else if(pre[v] < pre[u] && v != fa)
{
lowu = min(lowu,pre[v]);
}
}
if(fa < 0 && child == 1)
iscnt[u] = false;
low[u] = lowu;
return lowu;
}
int main()
{
int i,u,v;
scanf("%d %d",&n,&m);
for(i = 1;i <= m; i++)
{
scanf("%d %d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,-1);
int sum = 0;
for(i = 1;i <= n; i++)
if(iscnt[i])
sum++;
printf("%d\n",sum);
return 0;
}
记忆化搜索 就滑雪那样的 没有了4个方向 更简单了
题意看清就行
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char a[120][20];
int dp[120];
int vis[120];
int n;
bool ok1(char *s1,char *s2)
{
int i,j;
int cnt = 0;
int len = strlen(s1);
for(i = 0;i < len; i++)
{
if(s1[i] > s2[i])
return false;
if(s1[i] < s2[i])
{
for(j = i + 1;j < len; j++)
if(s2[i] == s1[j])
break;
if(j == len)
return false;
}
if(s1[i] != s2[i])
cnt++;
}
if(cnt != 1)
return false;
return true;
}
bool ok2(char *s1,char *s2)
{
int i,j;
int cnt = 0;
int len = strlen(s2);
for(i = 0;i < len; i++)
{
if(s1[i] != s2[i])
break;
}
if(i == len)
return true;
for(j = i,i = j + 1; j < len; i++,j++)
if(s1[i] != s2[j])
return false;
return true;
}
bool check(char *s1,char *s2)
{
if(strlen(s1) < strlen(s2))
return false;
else if(strlen(s1) == strlen(s2))
{
if(ok1(s1,s2))
return true;
}
else if(strlen(s1) - 1 == strlen(s2))
{
if(ok2(s1,s2))
return true;
}
return false;
}
int dfs(int u)
{
if(vis[u])
return dp[u];
int i;
int max = 0;
for(i = 1;i <= n; i++)
{
if(u == i)
continue;
if(!check(a[u],a[i]))
continue;
int temp = dfs(i);
if(max < temp)
max = temp;
}
dp[u] = max + 1;
vis[u] = true;
return dp[u];
}
int main()
{
int i,j;
while(scanf("%d",&n)!=EOF)
{
for(i = 1;i <= n; i++)
scanf("%s",a[i]);
memset(dp,0,sizeof(dp));
memset(vis,false,sizeof(vis));
int max = 0;
for(i = 1;i <= n; i++)
{
int temp = dfs(i);
if(max < temp)
max = temp;
}
printf("%d\n",max);
}
return 0;
}
不会啊 求告知
二维01背包 一不小心A了 一维也可以的
#include <cstdio>
#include <algorithm>
using namespace std;
struct node
{
int u;
int v;
}a[200];
bool dp[2][100000];
bool map[2][100000];
int main()
{
int n,i,j,k;
int m = 0;
int sum = 0;
while(scanf("%d",&n)!=EOF)
{
memset(dp,false,sizeof(dp));
memset(map,false,sizeof(map));
sum = 0;
for(i = 1;i <= n; i++)
{
scanf("%d %d",&a[i].u,&a[i].v);
sum += a[i].u + a[i].v;
}
map[1][0] = map[0][0] = true;
for(i = 1;i <= n; i++)
{
memcpy(dp,map,sizeof(map));
memset(map,false,sizeof(map));
for(j = m; j >= 0;j--)
{
if(dp[0][j])
{
map[0][j+a[i].u] = true;
map[0][j+a[i].v] = true;
m = max(m,j+a[i].u);
m = max(m,j+a[i].v);
}
if(dp[1][j])
{
map[1][j+a[i].u] = true;
map[1][j+a[i].v] = true;
m = max(m,j+a[i].u);
m = max(m,j+a[i].v);
}
}
}
for(i = sum/2 ;i >= 1; i--)
{
if(map[0][i] || map[1][i])
break;
}
printf("%d\n",sum-2*i);
}
return 0;
}