1039. Phone Home

本文探讨了蜂窝染色问题的解决方法,包括初始尝试的O(n^2)复杂度算法,以及后续的深搜算法验证。通过实例分析和代码实现,展示了如何在限制条件下求解问题,并提供了正确的解决方案。
染色问题初探。
问题就是模拟蜂窝染色。
方法一,对每个点,扫描周围相邻的每一个点,从1(颜色)开始,有重复则递增,会找到染本点的最小数字。

                所有点中最大的数即为总共需要的颜色数。O(n^2)的·复杂度。

              //  居然AC了...说明测试数据的局限性!!!.

              // 这个方法后来举个反例证明是错误的,如果按照度数由大到小的顺序搜索呢?也不知道对不对。

后来发现好像对着呢,,,把当初的疑惑注释掉....一下就是举得例子,发现当时算错了,也不能推翻我的算法


#include<stdio.h>
#include<cmath>
#include<cstring>
const double eps = 1e-8;


double x[12], y[12];
int map[12][12];
int n, tot;
int  color[12];
inline double dis(double x0, double y0, double x1, double y1){
       return sqrt( (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
}
void dfs(int k){
    if(!color[k]){
         int i , j, tc = 1;
         bool flg = 1;
         while(flg){
             flg = 0;
             for(i = 0; i < n; i++) if(map[k][i]){
                 if(tc == color[i]){
                     tc++; flg = 1;
                     break;
                 } 
             }
         }

         color[k] = tc;
  }
}
int main(){
   //freopen("in.txt", "r", stdin);
    int cas = 0;
    while(scanf("%d" , &n)!=EOF && n){
           cas++;
           int i, j;
           for(i = 0; i < n; i++ )scanf("%lf%lf", x + i, y + i);
           memset(map, 0, sizeof(map));
           memset(color, 0, sizeof(color));
           
           for(i = 0; i < n; i++){
               for(j = 0; j < n; j++)if(i != j){
                     if( dis(x[i], y[i], x[j], y[j]) <= 20 + eps)map[i][j] = 1;
               }
           }
          tot = 0;
          for(i = 0; i < n; i++){
              dfs(i);
              if(color[i] > tot)tot = color[i];
          }
          
      printf("The towers in case %d can be covered in %d frequencies.\n", cas, tot);
    }
}



正规解法是深搜,我加了注释。是lh 写的,有点难懂

#include <stdio.h>
#include <math.h>

const double eps = 1e-6;

typedef struct
{
	double x, y;
}POINT;

POINT tower[12];
int graph[12][12];
int color[12];
int n;

double dist(POINT a, POINT b)
{
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

int search(int dep, int num)//num种颜色可以成功么?
{
	int i, j;
	if (dep == n) return 1;
	for (i=0; i<num; i++)//dep 染 i 可以么?
	{   //当前只染到dep
		for (j=0; j<dep; j++) if (graph[dep][j] && color[j] == i) break;
		if (j < dep) continue;
		//以上2句:若果当前dep不能染 i ,继续i++。如果可以,则j>=dep,执行以下
		color[dep] = i;
		if (search(dep + 1, num)) return 1;
	}
	return 0;
}

int main()
{
	int cn, i, j;
	cn = 1;
	while (scanf("%d", &n), n > 0)
	{
		for (i=0; i<n; i++) scanf("%lf%lf", &tower[i].x, &tower[i].y);
		for (i=0; i<n; i++)
			for (j=0; j<n; j++)
				if (i != j && dist(tower[i], tower[j]) <= 20 + eps) graph[i][j] = 1; else graph[i][j] = 0;
		for (i=1; i<=5; i++)
		{
			color[0] = 0;
			if (search(1, i)) break;
		}
		printf("The towers in case %d can be covered in %d frequencies.\n", cn, i);
		cn ++;
	}
	return 0;
}


<think>我们被要求解释如何使用ContactsContract.CommonDataKinds.Phone.CONTENT_URI来访问联系人数据。 根据引用[1][2][4]中的代码示例,我们可以总结出以下步骤: 1. 获取ContentResolver对象。 2. 使用ContentResolver查询Phone.CONTENT_URI,该URI包含了联系人的电话号码信息。 3. 遍历Cursor,从中获取联系人的姓名和电话号码等字段。 引用[2]和[4]的代码示例展示了两种不同的写法,但都遵循了相同的模式。 注意:在Android中,访问联系人数据需要READ_CONTACTS权限。 下面我们将详细说明使用ContactsContract.CommonDataKinds.Phone.CONTENT_URI查询联系人的步骤。</think>### Android ContactsContract.CommonDataKinds.Phone.CONTENT_URI 使用方法详解 #### 一、基本查询流程 使用 `ContactsContract.CommonDataKinds.Phone.CONTENT_URI` 查询联系人电话数据的基本步骤: ```java // 1. 获取ContentResolver ContentResolver resolver = getContentResolver(); // 2. 定义查询字段 String[] projection = new String[] { Phone._ID, // 联系人ID Phone.DISPLAY_NAME, // 联系人姓名 Phone.NUMBER, // 电话号码 Phone.TYPE, // 号码类型(手机/家庭/工作等) Phone.LABEL // 自定义标签 }; // 3. 执行查询 Cursor cursor = resolver.query( Phone.CONTENT_URI, // 查询URI projection, // 返回字段 null, // WHERE条件 null, // WHERE参数 Phone.DISPLAY_NAME + " ASC" // 排序 ); // 4. 处理结果 if (cursor != null) { while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME)); String number = cursor.getString(cursor.getColumnIndex(Phone.NUMBER)); int type = cursor.getInt(cursor.getColumnIndex(Phone.TYPE)); // 获取号码类型描述 String typeLabel = (String) Phone.getTypeLabel( getResources(), type, cursor.getString(cursor.getColumnIndex(Phone.LABEL)) ); Log.d("Contact", name + ": " + number + " (" + typeLabel + ")"); } cursor.close(); // 必须关闭Cursor } ``` #### 二、关键参数说明 1. **URI常量**: - `Phone.CONTENT_URI`:所有电话号码数据 - `Phone.CONTENT_FILTER_URI`:带过滤条件的URI(如引用[3]所示)[^3] 2. **常用字段常量**: | 字段 | 说明 | |------|------| | `Phone._ID` | 数据记录ID | | `Phone.CONTACT_ID` | 联系人ID | | `Phone.DISPLAY_NAME` | 联系人显示名称 | | `Phone.NUMBER` | 电话号码 | | `Phone.TYPE` | 号码类型(`TYPE_MOBILE`等) | | `Phone.LABEL` | 自定义标签 | 3. **号码类型常量**: ```java Phone.TYPE_HOME // 家庭电话 Phone.TYPE_MOBILE // 手机 Phone.TYPE_WORK // 工作电话 Phone.TYPE_OTHER // 其他类型 ``` #### 三、高级查询技巧 1. **条件过滤**(引用[1][4]): ```java // 查询特定联系人的号码 String selection = Phone.CONTACT_ID + " = ?"; String[] selectionArgs = new String[]{ String.valueOf(contactId) }; Cursor phones = resolver.query( Phone.CONTENT_URI, null, selection, selectionArgs, null ); ``` 2. **模糊搜索**(引用[3]): ```java // 搜索包含"123"的电话号码 Uri searchUri = Uri.withAppendedPath( Phone.CONTENT_FILTER_URI, Uri.encode("123") ); Cursor result = resolver.query( searchUri, projection, null, null, null ); ``` 3. **批量插入**: ```java ArrayList<ContentProviderOperation> ops = new ArrayList<>(); ops.add(ContentProviderOperation.newInsert(Phone.CONTENT_URI) .withValue(Phone.NUMBER, "13800138000") .withValue(Phone.TYPE, Phone.TYPE_MOBILE) .withValue(Phone.RAW_CONTACT_ID, rawContactId) .build()); resolver.applyBatch(ContactsContract.AUTHORITY, ops); ``` #### 四、注意事项 1. **权限要求**: ```xml <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/> <!-- 修改时 --> ``` 2. **性能优化**: - 使用投影减少数据量(避免`SELECT *`) - 在后台线程执行查询(避免主线程阻塞) - 及时关闭Cursor(防止内存泄漏) 3. **数据变化监听**: ```java resolver.registerContentObserver( Phone.CONTENT_URI, true, // 监听子URI new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { // 联系人数据变化时触发 } } ); ``` #### 五、完整示例 ```java public List<Contact> getAllContacts(Context context) { List<Contact> contacts = new ArrayList<>(); ContentResolver resolver = context.getContentResolver(); try (Cursor cursor = resolver.query( Phone.CONTENT_URI, new String[]{Phone.DISPLAY_NAME, Phone.NUMBER, Phone.TYPE}, null, null, Phone.DISPLAY_NAME + " ASC" )) { if (cursor != null) { int nameIndex = cursor.getColumnIndex(Phone.DISPLAY_NAME); int numIndex = cursor.getColumnIndex(Phone.NUMBER); int typeIndex = cursor.getColumnIndex(Phone.TYPE); while (cursor.moveToNext()) { Contact contact = new Contact(); contact.name = cursor.getString(nameIndex); contact.number = cursor.getString(numIndex); contact.type = Phone.getTypeLabelResource(type); contacts.add(contact); } } } catch (SecurityException e) { Log.e("Contacts", "权限不足: " + e.getMessage()); } return contacts; } ``` > **最佳实践**:对于需要频繁访问联系人数据的应用,建议使用`CursorLoader`或`Room`等现代Android架构组件管理数据加载[^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值